#include <VCL.h>
#include <Registry.hpp>
#include <Math.h> //Pour pow
#include <Math.hpp>

// Prototypes standards
#include <StdLib.h>
#include <StdIO.h>
#include <Limits.h>
#include <IO.h>
#include <FCntl.h>
#include <Sys\Stat.h>
#include <Share.h>
#include <ErrNo.h>
#include <FileCtrl.hpp> //Pour ForceDirectories
#include <list>

#pragma hdrstop

#include "imapi.h"

// Prototypes du projet
#include "EICVer.h"
#include "EIC.h"
#include "MTAG_EIC.h"
#include "uDates.h" //Pour IsBissextile

USERC("EICRes.rc");
USERC("Version.rc");
USE("EIC.h", File);
USE("EICDossi.h", File);
USE("EICVer.h", File);
USE("VerAss32.h", File);
USEUNIT("EICDOS.cpp");
USEFORM("uBarre.cpp", frmBarre);
USEFORM("uFileOp.cpp", dlgFileOperation);
USEPACKAGE("vcl50.bpi");
USEPACKAGE("vclx50.bpi");
USEFORM("uCopier.cpp", dlgCopierFichiers);
USE("PROTECT.H", File);
USEUNIT("uMigrations.cpp");
USEUNIT("uDates.cpp");
USEUNIT("uNombre.cpp");
USEUNIT("uSousClasse.cpp");
USEUNIT("uParamCourrierEtCarnAdr.cpp");
USEUNIT("uListeLangues.cpp");
USEUNIT("uListePays.cpp");
USEUNIT("uFormatsPapier.cpp");
USEUNIT("CCurrency.cpp");
USEUNIT("uListeDepartements.cpp");
//---------------------------------------------------------------------------
#pragma package(smart_init)
static void __fastcall UnloadVisas();
#pragma exit UnloadVisas

#define MODULE_TAG MTAG_EIC

#define SWAPWORDS(X) ( (X<<16) | (X>>16) )

//---------------------------------------------------------------------------
//   Source du paquet.
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
    return 1;
}

//*****************************//
// Variables privées du module //
//*****************************//
static TImageList* _pimglstVisas = NULL;       // Liste des images des visas
VER_PLATFORM       _WINPLATFORM  = VP_UNKNOWN; // Type de la platform dans lequel l'appli évolue
Graphics::TBitmap *_pbmpArrow[2] = {NULL, NULL};

#define STDIDB_VISAS_RESOURCE_NAME "Visas"  // Nom de la ressource Bitmap des visas standards
#define STDIDB_VISAS_COUNT         ( STDIDB_VISA_LAST - STDIDB_VISA_FIRST + 1)
#define MAX_MSG_LEN                2048     // Compris le '\0' terminal



#ifdef _DEBUG
// static bool _bAssert     = true;  // TRUE pour gérer les assertions
// static bool _bCoolAssert = false; // TRUE pour transformer les assertions en avertissements


/*****************************************************************************\
************* Assert() ********************************************************
*******************************************************************************
*                                                                             *
*    Cette procédure - visible en mode _DEBUG uniquement - est exécutée       *
* lorsqu'une assertion n'est pas vérifiée. Elle affiche un message qui permet *
* de localiser l'assertion et termine le programme.                           *
\*****************************************************************************/
void __fastcall Assert( unsigned long ulLineNb, const char* pcszSourceFile,const char* Fonction)
{
   AnsiString strTitre( EICFormat( "Assertion non vérifiée ligne n° %lu", ulLineNb));
   AnsiString strMsg(   EICFormat( "Fichier : \"%s\"\nFonction : \"%s\"\n\n%s",pcszSourceFile,Fonction, /*_bCoolAssert ? */"Voulez-vous quand même continuer l'exécution ?"/* : "L'application va se terminer..."*/));

   TRACE( "%s : %s", strTitre.c_str(), strMsg.c_str());

   if( EICMsgBox( strMsg.c_str(), strTitre.c_str(), /*_bCoolAssert ? */( MB_YESNO | MB_ICONSTOP | MB_APPLMODAL | MB_TOPMOST) /*: ( MB_OK | MB_ICONSTOP | MB_APPLMODAL | MB_TOPMOST)*/) != IDYES)
     Application->Terminate();
}


void _AfficheLastError( unsigned long ulLineNb, const char* pcszSourceFile,const char* Fonction, const AnsiString &Titre, const AnsiString &Message)
{
   LPVOID lpMsgBuf;
   int LastError = GetLastError( );
   FormatMessage(
	      FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
	      NULL,
	      LastError,
	      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
	      (LPTSTR) &lpMsgBuf,
	      0,
	      NULL
	      );
   AnsiString strMsg(   EICFormat( "Fichier : \"%s\"\nFonction : \"%s\"\nLigne : %lu\n\n[%d] %s",
                        pcszSourceFile,Fonction, ulLineNb, LastError, (char*)lpMsgBuf));
   if (!Message.IsEmpty())
     strMsg = Message + "\n\n" + strMsg;
   Application->MessageBox( strMsg.c_str(), Titre.IsEmpty()?"Erreur":Titre.c_str(), MB_OK | MB_ICONERROR);
   LocalFree( lpMsgBuf );
}

void __cdecl TRACE( const AnsiString& asFormat, const TVarRec *args, int size)
{
   ::OutputDebugString( AnsiString::Format(asFormat, args, size).c_str());
}

void __cdecl TRACE( const char* szFormat, ...)
{
   char szBuff[ 80*4];
   va_list marker;
   memset(szBuff,0,sizeof(szBuff));
   ASSERT( szFormat);
   va_start( marker, szFormat );
   vsprintf( szBuff, szFormat, marker );
   ASSERT_VALID_STRING( szBuff);
   ::OutputDebugString( szBuff);
/*
   static HWND hEditDebug = 0;
   if( hEditDebug == 0)
   {
       AnsiString  Cle       = "\\SOFTWARE\\EIC\\DebugWin",
		   ValClasse = "ClasseFenetreMere",
		   ValNom    = "NomFenetreMere",
		   ValIDEdit = "IDEdit";
       AnsiString Classe, Nom;
       int        IDEdit;
       TRegistry *pReg = new TRegistry;
       pReg->RootKey = HKEY_LOCAL_MACHINE;
       if( !pReg->KeyExists( Cle) && pReg->OpenKey(Cle, true))
       {
	   Classe = "DBWin";
	   Nom    = "Debug Messages";
	   IDEdit = 0;
	   pReg->WriteString( ValClasse, Classe);
	   pReg->WriteString( ValNom, Nom);
	   pReg->WriteInteger( ValIDEdit, IDEdit);
       }
       else if( pReg->OpenKey(Cle, false))
       {
	   Classe = pReg->ReadString( ValClasse);
	   Nom    = pReg->ReadString( ValNom);
	   IDEdit = pReg->ReadInteger( ValIDEdit);
       }
       else return;
       pReg->CloseKey();
       delete pReg;

       HWND h = ::FindWindow( Classe.c_str(), Nom.c_str());
       if( h)   hEditDebug = GetDlgItem( h, IDEdit);
       else     hEditDebug = (HWND)-1;
 }
 if( hEditDebug && (hEditDebug != (HWND)-1))
 {
    ::SendMessage( hEditDebug, EM_SETSEL, 32767, 32767);
    ::SendMessage( hEditDebug, EM_REPLACESEL, (WPARAM)1, (LPARAM)(LPCTSTR)szBuff);
 }
*/
 }



bool __fastcall IsMachine(const AnsiString &Nom)
{
  const char *Informaticiens[] =
  {
    "ALEXP",
    "ALEXDEP",
    "AXELF",
    "ANTHONYM",
    "ARNAUDS",
    "CEDRICD",
    "DAVIDR",
    "ERICC",
    "FANNYM",
    "FREDERICHE",
    "GAELLEP",
    "KARENB",
    "KRISTELL",
    "LAURENTF",
    "LUDOVICVA",
    "PASCALEF",
    "RAPHAELL",
    "SOFIANEA",
    "SONIAM",
    "XAVIERP",
    "YORANM",
    NULL,
  };
  char sNom[255];
  bool Resultat = false;
  unsigned long Taille = 255,Position = 0;
  AnsiString NomUtilisateur;
  try
    {
      if (GetUserName(sNom,&Taille))
        {
          NomUtilisateur = AnsiString(sNom).UpperCase();
          if (Nom.IsEmpty())
            while (Informaticiens[Position])
              {
                if (NomUtilisateur == Informaticiens[Position])
                  {
                    Resultat = true;
                    break;
                  }
                Position++;
              }
          else
            Resultat = NomUtilisateur == Nom.UpperCase();
        }
    }
  catch (...)
    {
    }
  return Resultat;
}



 AnsiString __fastcall EICComponentName( TComponent* pComp)
 {
  if( pComp == NULL) return "\"Component is NULL\"";
  else if( dynamic_cast<TComponent*>( pComp) == NULL) return "\"Component is not TComponent* dynamically castable\"";
  else
  { AnsiString strName( pComp->Name + "\"");

    while( !dynamic_cast<TForm*>( pComp))
      if( ( pComp = pComp->Owner) != NULL) strName = pComp->Name + "." + strName;
      else                                 break;
    return "\"" + strName;
  }
 }
#else
void __fastcall Assert( unsigned long ulLineNb, const char* pcszSourceFile,const char* Fonction)
{
}
#endif


UINT __fastcall EICMsgBox(const AnsiString &ChaineMessage,const AnsiString &ChaineTitre,UINT uType)
{
  return EICMsgBox(ChaineMessage.c_str(),ChaineTitre.c_str(),uType);
};



bool __fastcall EICQuestion(const AnsiString &ChaineMessage,const AnsiString &ChaineTitre,UINT uType)
{
  return EICQuestion(ChaineMessage.c_str(),ChaineTitre.c_str(),uType);
};


bool __fastcall EICOkAnnuler(const AnsiString &ChaineMessage,const AnsiString &ChaineTitre,UINT uType)
{
  return EICOkAnnuler(ChaineMessage.c_str(),ChaineTitre.c_str(),uType);
};


bool __fastcall EICErreur(const AnsiString &ChaineMessage)
{
  return EICErreur(ChaineMessage.c_str());
};


void __fastcall EICAttention(const AnsiString &ChaineMessage)
{
  EICAttention(ChaineMessage.c_str());
};

/*----------------------------------------------------------------------------*\
-------------- LoadVisas() -----------------------------------------------------
--------------------------------------------------------------------------------
-                                                                              -
-    Cette fonction permet de charger la ressource "Visas" qui représente les  -
- divers visas standards EIC.                                                -
-                                                                              -
- Retour :                                                                     -
-   TRUE si les visas sont bien, ou déjà, chargés; FALSE sinon.                -
\*----------------------------------------------------------------------------*/
static void __fastcall UnloadVisas()
{
  delete _pimglstVisas;
  _pimglstVisas = 0;
}



static bool __fastcall LoadVisas()
{
 bool bOk; // TRUE si la ressource est bien chargée
 // Vérification de l'utilité de l'opération //
 if( _pimglstVisas != NULL)
 { // les visas sont déjà chargés
   return true;
 }
 // Chargement de la ressource "Visas" //
 // Création de la liste des visas
 bOk = false;
 try {
   _pimglstVisas = new TImageList( /*Applicationtoto*/0);

   #ifdef _DEBUG
    if( ( _pimglstVisas->BlendColor != clNone) ||
	( _pimglstVisas->DrawingStyle != dsNormal) ||
	!_pimglstVisas->Masked ||
	_pimglstVisas->ShareImages)
      ::MessageBox( 0, "Pb de définition de la liste des visas standards...", "Resource.dll::Attention", MB_ICONWARNING);
   #endif

   _pimglstVisas->AllocBy    = STDIDB_VISAS_COUNT;
   _pimglstVisas->Height     = STDIDB_VISAS_HEIGHT;
   _pimglstVisas->Width      = STDIDB_VISAS_WIDTH;
   _pimglstVisas->BkColor    = clWhite;             // BkColor quelconque pour les visas sélectionnés dans une grille par ex.
   _pimglstVisas->ImageType  = itMask;              // Le Bitmap des visas représente en fait des masques de visas

   if( _pimglstVisas->ResInstLoad( (int)HInstance, rtBitmap, STDIDB_VISAS_RESOURCE_NAME, clWhite))
     if( _pimglstVisas->Count == STDIDB_VISAS_COUNT)
     { // Bitmaps des visas correctement chargés
       bOk = true;
     }
 } catch(...) {
   // Erreur de chargement des visas
   // => On détruit la liste des visas qui n'est pas bien créée
   #ifdef _DEBUG
    ::MessageBox( 0, "Pb de chargement des visas standards...", "Resource.bpk::Attention", MB_ICONWARNING);
   #endif
   delete _pimglstVisas;
   _pimglstVisas = NULL;
 }
 return bOk;
} /* LoadVisas() */


/*----------------------------------------------------------------------------*\
------------- ModuleShortName() ------------------------------------------------
--------------------------------------------------------------------------------
-                                                                              -
-    Cette fonction retourne le nom court (épuré de son éventuel chemin) d'un  -
- module.                                                                      -
-                                                                              -
- Paramètres :                                                                 -
-   hInstance        : Instance du module dont on veut obtenir le nom.         -
-   szFullModulePath : Buffer de stockage du nom à retourner.                  -
-                                                                              -
- Retour :                                                                     -
-   Un pointeur à l'intérieur du buffer sur le nom court du module.            -
-                                                                              -
- Note : Si le handle d'instance fourni ne correspond àaucun module, le nom    -
-        "?" est retourné.                                                     -
\*----------------------------------------------------------------------------*/
static
char* __fastcall ModuleShortName( void* hInstance,
				  char  szFullModulePath[ _MAX_PATH])
{
 char* pszModuleShortName;

 ASSERT( szFullModulePath);
 ASSERT( !::IsBadReadPtr( szFullModulePath, _MAX_PATH) &&
	 !::IsBadWritePtr( szFullModulePath, _MAX_PATH));

 if( ::GetModuleFileName( hInstance, szFullModulePath, _MAX_PATH) > 0)
 { // Nom du module bien lu
   ASSERT( strlen( szFullModulePath) < _MAX_PATH);
   // => Extraction du nom court (sans le chemin)
   if( ( pszModuleShortName = strrchr( szFullModulePath, '\\')) == NULL)
   { // Nom court directement donné par le système
     return szFullModulePath;
   }
   else
   { // Nom court bien extrait
     return pszModuleShortName + 1;
   }
 }
 else
 { // Lecture du nom du module impossible
   // => Nom = "?"
   *(WORD*)szFullModulePath = MAKEWORD( '\?', '\0');
   return szFullModulePath;
 }
}



/*----------------------------------------------------------------------------*\
------------- DecorateOrigin() -------------------------------------------------
--------------------------------------------------------------------------------
-                                                                              -
-    Cette fonction retourne une chaîne qui "décore" l'origine d'une exception -
- EUser si le module appelant n'est pas le même que celui qui a levé           -
- l'exception ou bien, si l'exception n'est pas de type EUser, retourne le nom -
- de sa classe.                                                                -
-                                                                              -
- Paramètres :                                                                 -
-   hInstance : Instance du module appelant.                                   -
-   e         : Exception EUser dont on veut "décorer" l'origine ou autre      -
-               exception dont on veut connaître le nom de classe.             -
-                                                                              -
- Retour :                                                                     -
-   EUser: Origine de l'exception éventuellement décorée sous la forme :       -
-          "("NomModule":"Chaine")"                                            -
-   Autre: Nom de sa classe.                                                   -
\*----------------------------------------------------------------------------*/
// Désactive les messages "Non-const function _fastcall System::TObject::InheritsFrom(System::TMetaClass*)/System::TObject::ClassName() called for const object."
#pragma warn -ncf
static
AnsiString __fastcall DecorateOrigin( void*            hInstance,
				      const Exception& e)
{
 ASSERT( hInstance);
 ASSERT( dynamic_cast<const Exception*>( &e));


 if( e.InheritsFrom( __classid( EUser)))
 {
  if( hInstance != ((const EUser&)e).HInst)
   { // Le module appelant est différent de celui qui a levé l'exception
     // => Décoration de l'origine de l'exception
     char szFullModulePath[ _MAX_PATH + 1];

     *szFullModulePath = '(';
     return ModuleShortName( ((const EUser&)e).HInst, szFullModulePath + 1) +
	     AnsiString( ":") + ((const EUser&)e).Origine +
	     ")";
   }
   else
   { // Le module appelant est celui qui a levé l'exception
     // => Pas de décoration de l'origine
     return ((const EUser&)e).Origine;
   }
 }
 else
   return e.ClassName();    // Retour du nom de classe
} /* DecorateOrigin() */
#pragma warn .ncf
// Réactive les messages "Non-const function ? called for const object."



/******************************************************************************\
************* EICvFormat() *****************************************************
********************************************************************************
*                                                                              *
*    Cette fonction permet de formater des données au style printf.            *
*                                                                              *
* Paramètres :                                                                 *
*   pcszFormat : Chaîne de formatage (ou IDS d'une chaîne de formatage)        *
*   lstArgs    : Liste des arguments à formater                                *
*                                                                              *
* Retour :                                                                     *
*   Les arguments formatés selon le format spécifié.                           *
\******************************************************************************/
AnsiString __fastcall EICvFormat( const char* pcszFormat, // MAKEINTRESOURCE accepté
				  va_list     lstArgs)
{
 AnsiString strFormat; // Chaîne de formatage
 AnsiString strResult; // Arguments formatés

 if (!pcszFormat)
  return EmptyStr;

 ASSERT( pcszFormat && lstArgs);

 strResult.SetLength( MAX_MSG_LEN);
 // Récupération éventuelle de la chaîne de formatage depuis les ressources //
 if( HIWORD( pcszFormat) == 0)
 { // Il s'agit d'une chaîne de ressources à prendre comme chaîne de formatage
   strFormat = EICResStr( pcszFormat);

   ASSERT( !strFormat.IsEmpty()); // Si la chaîne de ressource n'est pas trouvée, EICResStr retourne un msg d'erreur à la place de la chaîne
   pcszFormat = strFormat.c_str();
 }
 // Formatage des données //
 vsprintf( strResult.c_str(), pcszFormat, lstArgs);

 ASSERT( strlen( strResult.c_str()) < MAX_MSG_LEN);

 strResult.SetLength( strlen( strResult.c_str()));
 return strResult;
}


/******************************************************************************\
************* EICFormat() ******************************************************
********************************************************************************
*                                                                              *
*    Cette fonction permet de formatter des données au style printf.           *
*                                                                              *
* Paramètres :                                                                 *
*   pcszFormat : Chaîne de formatage (ou IDS d'une chaîne de formatage)        *
*   ...        : Arguments à formater                                          *
*                                                                              *
* Retour :                                                                     *
*   Les arguments formatés selon le format spécifié.                           *
\******************************************************************************/
AnsiString __cdecl EICFormat( const char* pcszFormat, // MAKEINTRESOURCE accepté
			      ...)
{
 va_list lstArgs; // Liste des arguments à formater
 va_start( lstArgs, pcszFormat);          // Préparation au formatage des données
 return EICvFormat( pcszFormat, lstArgs);
}


/******************************************************************************\
************* EICCharToOem() ***************************************************
********************************************************************************
*                                                                              *
*    Cette fonction permet de convertir une chaine Windows en une chaine DOS.  *
*    Voir aussi le SDK pour plus d'information.                                *
*                                                                              *
* Paramètres :                                                                 *
*   strVal : Chaîne à tranformer                                               *
*                                                                              *
* Retour :                                                                     *
*   La chaine transformée.                                                     *
\******************************************************************************/
AnsiString __fastcall EICCharToOem( const AnsiString &strVal)
{
  /*char szBuffer[1024]; ASSERT( strVal.Length()<1024);

  ::CharToOem( strVal.c_str(), szBuffer);
  return AnsiString( szBuffer);*/

  char       *szBuffer;
  AnsiString strBuffer;

  szBuffer  = new char[strVal.Length()+1];
  ::CharToOem( strVal.c_str(), szBuffer);
  strBuffer = szBuffer;

  delete []szBuffer;
  return  strBuffer;
}

/******************************************************************************\
************* EICOemToChar() ***************************************************
********************************************************************************
*                                                                              *
*    Cette fonction permet de convertir une chaine DOS en une chaine Windows.  *
*    Voir aussi le SDK pour plus d'information.                                *
*                                                                              *
* Paramètres :                                                                 *
*   strVal : Chaîne à tranformer                                               *
*                                                                              *
* Retour :                                                                     *
*   La chaine transformée.                                                     *
\******************************************************************************/
AnsiString __fastcall EICOemToChar( const AnsiString &strVal)
{
  /*char szBuffer[1024]; ASSERT( strVal.Length()<1024);

  ::OemToChar( strVal.c_str(), szBuffer);
  return AnsiString( szBuffer);*/

  char       *szBuffer;
  AnsiString strBuffer;

  szBuffer  = new char[strVal.Length()+1];
  ::OemToChar( strVal.c_str(), szBuffer);
  strBuffer = szBuffer;

  delete []szBuffer;
  return  strBuffer;
}


/******************************************************************************\
************* EICResStr() ******************************************************
********************************************************************************
*                                                                              *
*    Cette fonction permet permet de lire une ressource chaîne.                *
*                                                                              *
* Paramètres :                                                                 *
*   pcszIDS : ID d'une ressource chaîne ou, à défaut, une chaîne.              *
*                                                                              *
* Retour :                                                                     *
*   La chaîne lue dans les ressources (si pcsz est un ID de ressources) ou     *
* bien la chaîne elle-même.                                                    *
\******************************************************************************/
AnsiString __fastcall EICResStr( const char* pcszIDS)
{
 ASSERT( pcszIDS);

 if( HIWORD( pcszIDS) == 0)
 { // C'est une ressource...
   if( IS_RESOURCE_STD( pcszIDS))
   { //...standard (contenue dans le paquet EIC.bpl)
     char szBuf[ 1024];

     if( ::LoadString( HInstance, (UINT)pcszIDS, szBuf, sizeof( szBuf)) <= 0)
       sprintf( szBuf, "(Ressource chaîne standard n° %u non trouvée)", (UINT)pcszIDS);

     return AnsiString( szBuf);
   }
   else
   { //...quelconque
     AnsiString str( AnsiString::LoadStr( (int)pcszIDS));

     if( str.IsEmpty())
       return EICFormat( "Ressource manquante: IDS_%i", (int)pcszIDS);
     else
       return str;
   }
 }
 else
   return AnsiString( pcszIDS);
}


/******************************************************************************\
************* EICMsgBox() ******************************************************
********************************************************************************
*                                                                              *
*    Cette fonction affiche un message dans un dialogue et retourne la réponse *
* de l'utilisateur à ce message.                                               *
*                                                                              *
* Paramètres :                                                                 *
*   pcszMsg   : Contenu du message               (IDS accepté)                 *
*   pcszTitre : Titre du dialogue du message     (IDS accepté)                 *
*   uType     : Type du dialogue (types MB_APPLMODAL | MB_SETFOREGROUND        *
*               automatiquement mis).                                          *
*                                                                              *
* Retour :                                                                     *
*   La réponse de l'utilisateur (une valeur ID*)                               *
*                                                                              *
* Note : L'implémentation de cette fonction est inspirée de celle de           *
*        Application::MessageBox() proposée par Borland dans le fichier        *
*        SOURCE\VCL\FORMS.PAS mais modifiée pour accepter les drapeaux 32bits  *
*        dans le dernier paramètre de ::MessageBox().                          *
\******************************************************************************/
typedef std::list<HWND> ListeHandle;
ListeHandle _LH;
typedef HWND (*GetFenetreEnCoursFCT)();
HWND __fastcall HandleDeLaFenetreActiveEICShell()
{
  GetFenetreEnCoursFCT GetFenetreEnCours;
  HMODULE hmEICShell = GetModuleHandle("EICShell.dll");
  GetFenetreEnCours = (GetFenetreEnCoursFCT)GetProcAddress(hmEICShell,"GetFenetreEnCours");
  return GetFenetreEnCours();
}


void __fastcall EmpilerFenetre(HWND Handle)
{
  SetWindowLong(Handle,GWL_HWNDPARENT,(long)HandleDeLaFenetreActiveEICShell());
  _LH.push_back(Handle);
}


void __fastcall DepilerFenetre(HWND Handle)
{
  if (_LH.size() && (_LH.back() == Handle))
    _LH.pop_back();
}


UINT __fastcall EICMsgBox( const char* pcszMsg,   // MAKEINTRESOURCE accepté
			   const char* pcszTitre, // MAKEINTRESOURCE accepté
			   UINT        uType)     // MB_APPLMODAL | MB_SETFOREGROUND automatiques
{
 UINT  uResult;      // Retour de la fonction

 ASSERT(pcszMsg);
 ASSERT(pcszTitre);

 AnsiString strMsg( EICResStr( pcszMsg));
 AnsiString strTitre( EICResStr( pcszTitre));
 // Désactivation de toutes les fenêtres du processus //
 try {
   //hwndFenetreEICShell pour éviter qu'EICShell passe devant les messages Builder
   uResult = ::MessageBox( hwndFenetreEICShell ? (_LH.size() ? _LH.back() : HandleDeLaFenetreActiveEICShell()) : (Screen->ActiveForm ? Screen->ActiveForm->Handle : 0)/*Application->Handle*/,
			   strMsg.c_str(),
			   strTitre.c_str(),
			   uType | /*MB_APPLMODAL*/MB_TASKMODAL | MB_SETFOREGROUND);
 } catch(...) {
   uResult = IDABORT;
 }
 // Réactivation de toutes les fenêtres du processus //
 return uResult;
}

/******************************************************************************\
************* EICQuestion() ****************************************************
********************************************************************************
*                                                                              *
*    Cette fonction affiche une question à laquelle l'utilisateur doit répondre*
* par Oui ou Non. Elle indique si l'utilisateur a répondu "Oui".               *
*                                                                              *
* Paramètres :                                                                 *
*   pcszQuestion : Contenu de la question           (IDS accepté)              *
*   pcszTitre    : Titre du dialogue de la question (IDS accepté)              *
*   uType        : Type du dialogue (types MB_ICONEQUESTION | MB_YESNO et      *
*                  MB_APPLMODAL | MB_SETFOREGROUND automatiquement mis).       *
*                                                                              *
* Retour :                                                                     *
*   TRUE si l'utilisateur répond Oui à la question; FALSE sinon.               *
\******************************************************************************/
bool __fastcall EICQuestion( const char* pcszQuestion,   // MAKEINTRESOURCE accepté
			     const char* pcszTitre,      // MAKEINTRESOURCE accepté
			     UINT        uType /* = 0*/ // MB_ICONQUESTION | MB_YESNO | MB_APPLMODAL | MB_SETFOREGROUND automatiques
			     )
{
 ASSERT(!(uType & MB_ICONQUESTION));   //On ne doit mettre MB_ICONQUESTION, il est automatique
 ASSERT(!(uType & MB_YESNO));          //On ne doit mettre MB_YESNO, il est automatique
 ASSERT(!(uType & ~MB_DEFBUTTON2));    //Le seul paramètre utilisable est MB_DEFBUTTON2
 #ifdef _DEBUG
   if (IS_MACHINE_INFORMATICIEN() && (uType & ~(MB_DEFBUTTON2)))
    EICErreur("Seul le paramètre MB_DEFBUTTON2 est possible pour EICQuestion !");
 #endif

 return EICMsgBox(pcszQuestion,pcszTitre,uType | MB_ICONQUESTION | MB_YESNO) == IDYES;
}


bool __fastcall EICOkAnnuler( const char* pcszQuestion,   // MAKEINTRESOURCE accepté
			     const char* pcszTitre,      // MAKEINTRESOURCE accepté
			     UINT        uType /* = 0*/ // MB_ICONQUESTION | MB_YESNO | MB_APPLMODAL | MB_SETFOREGROUND automatiques
			     )
{
 ASSERT(!(uType & MB_ICONQUESTION));   //On ne doit mettre MB_ICONQUESTION, il est automatique
 ASSERT(!(uType & MB_YESNO));          //On ne doit mettre MB_YESNO, il est automatique
 ASSERT(!(uType & ~MB_DEFBUTTON2));    //Le seul paramètre utilisable est MB_DEFBUTTON2
 #ifdef _DEBUG
   if (IS_MACHINE_INFORMATICIEN() && (uType & ~(MB_DEFBUTTON2)))
    EICErreur("Seul le paramètre MB_DEFBUTTON2 est possible pour EICOkAnnuler !");
 #endif

 return EICMsgBox(pcszQuestion,pcszTitre,uType | MB_ICONQUESTION | MB_OKCANCEL) == IDOK;
}


bool __fastcall EICReessayer(const AnsiString &ChaineMessage,const AnsiString &ChaineTitre,UINT uType)
{
  return EICMsgBox(ChaineMessage.c_str(),ChaineTitre.c_str(),uType | MB_RETRYCANCEL) == IDRETRY;
}



/******************************************************************************\
************* EICErreur() ******************************************************
********************************************************************************
*                                                                              *
*    Cette fonction affiche un message d'erreur standard.                      *
*                                                                              *
* Paramètres :                                                                 *
*   pcszErrMsg : Message d'erreur à afficher (ou IDS accepté); NULL (ou        *
*                MAKEINTRESOURCE( 0)) signale qu'il n'y a pas d'erreur.        *
*                                                                              *
* Retour :                                                                     *
*   TRUE si la fonction a été appellée pour afficher une erreur; FALSE sinon   *
* (i.e. les traitements peuvent continuer normalement).                        *
\******************************************************************************/
bool __fastcall EICErreur( const char* pcszErrMsg) // MAKEINTRESOURCE accepté
{
 if( pcszErrMsg)
 { // Il faut afficher un message d'erreur
   EICMsgBox( EICFormat( "%s\n\nAbandon de l'opération.", EICResStr( pcszErrMsg).c_str()).c_str(),
			  "Erreur",
			  MB_OK | MB_ICONSTOP | MB_TOPMOST);

   return true;
 }
 else
   return false;                  // Il ne s'agit pas d'une erreur
}



/******************************************************************************\
************* EICAttention() ***************************************************
********************************************************************************
*                                                                              *
*    Cette fonction affiche un message d'avertissement standard.               *
*                                                                              *
* Paramètres :                                                                 *
*   pcszMsg : Contenu de l'avertissement (IDS accepté)                         *
\******************************************************************************/
void __fastcall EICAttention(const char* pcszMsg)
{                                                              
  EICMsgBox(pcszMsg,"Attention",MB_OK | /*MB_ICONINFORMATION*/MB_ICONWARNING | MB_TOPMOST);
}


void __fastcall EICInformation(const AnsiString &ChaineMessage)
{                                                              
  EICMsgBox(ChaineMessage.c_str(),"Information",MB_OK | MB_ICONINFORMATION | MB_TOPMOST);
}


/******************************************************************************\
************* EICDisplayException() ********************************************
********************************************************************************
*                                                                              *
*    Cette procédure affiche le détail (Origine + message) d'une exception.    *
*                                                                              *
* Paramètres :                                                                 *
*   tag       : TAG de localisation de l'appelant.                             *
*   e         : Exception à afficher.                                          *
*   hInstance : Instance du module appelant.                                   *
\******************************************************************************/
void __fastcall EICDisplayException( EICTag           tag,
									 const Exception& e,
									 void*            hInstance /* = HInstance */)
{
 char szFullModulePath[ MAX_PATH]; // Nom du module qui affiche l'exception
 EICMsgBox( EICFormat( "Module : %s\n\nErreur détectée en %s\n\nOrigine : %s\n\nErreur : \"%s.\"",
					   ModuleShortName( hInstance, szFullModulePath),
					   EICTagToStr( tag).c_str(),
					   DecorateOrigin( hInstance, e).c_str(),
					   e.Message.c_str()
					 ).c_str(),
			"Erreur d'exécution",
			MB_OK | MB_ICONSTOP | MB_TOPMOST);
}



void __fastcall EICDisplayException(const Exception &e,unsigned int Ligne,const AnsiString &Fichier,void *hInstance)
{
  char szFullModulePath[MAX_PATH]; //Nom du module qui affiche l'exception
  EICMsgBox(EICFormat("Erreur : '%s'\n\nModule : %s\nFichier : %s\nLigne : %u",
                      e.Message,
                      ModuleShortName(hInstance,szFullModulePath),
                      ExtractFileName(Fichier),
                      Ligne).c_str(),
			      "Erreur d'exécution",
			      MB_OK | MB_ICONSTOP | MB_TOPMOST);
}



AnsiString __fastcall EICMessageException(EICTag tag,const Exception &e,void *hInstance)
{
 char szFullModulePath[MAX_PATH];
 return EICFormat("Module : %s\n"
		  "\n"
		  "Erreur détectée en %s\n"
		  "\n"
		  "Origine : %s\n"
		  "\n"
		  "Erreur : \"%s.\"",
						ModuleShortName(hInstance,szFullModulePath),
						EICTagToStr(tag).c_str(),
				    DecorateOrigin(hInstance,e).c_str(),
				    e.Message.c_str()
					 );
}




/******************************************************************************\
************* EICDisplayExceptionMsg() *****************************************
********************************************************************************
*                                                                              *
*    Cette procédure affiche le message d'une exception (généralement capturée *
* dans un catch typé qui permet de continuer proprement l'application sans     *
* propager l'exception en question) en lui ajoutant un éventuel message qui    *
* indique la suite (ou l'issue) du traitement (genre : "Commande annulée"...). *
*                                                                              *
* Paramètres :                                                                 *
*   e            : Exception contenant le message à afficher.                  *
*   pcszMsgIssue : Message qui indique l'issue du traitement (IDS accepté)     *
*                  (NULL = "Commande annulée").                                *
*   pcszTitre    : Titre de la boite du message (IDS accepté) (NULL pour le    *
*                  titre par défaut : "Anomalie d'exécution").                 *
*   hInstance    : Instance du module appelant.                                *
*                                                                              *
* Retour :                                                                     *
*   La chaîne lue dans les ressources (si pcsz est un ID de ressources) ou     *
* bien la chaîne elle-même.                                                    *
\******************************************************************************/
void __fastcall EICDisplayExceptionMsg( const Exception& e,
										const char*      pcszMsgIssue, /* = NULL*/
										const char*      pcszTitre, /* = NULL */
										void*            hInstance /* = HInstance*/)
{
 char szFullModulePath[ MAX_PATH];
 EICMsgBox( EICFormat( "Module : %s\nOrigine : %s\n\n%s\n\n%s",
		       ModuleShortName( hInstance, szFullModulePath),
		       DecorateOrigin( hInstance, e).c_str(),
		       e.Message.c_str(),
		       EICResStr( pcszMsgIssue ? pcszMsgIssue : "Commande annulée.").c_str()
		     ).c_str(),
	    pcszTitre ? EICResStr( pcszTitre).c_str() : "Anomalie d'exécution",
	    MB_OK | MB_ICONEXCLAMATION | MB_TOPMOST);
}


/******************************************************************************\
************** DrawVisa() ******************************************************
********************************************************************************
*                                                                              *
*    Cette procédure permet de dessiner un visa standard sur un canvas.        *
*                                                                              *
* Paramètres :                                                                 *
*   pCanvas    : Canvas dans lequel dessiner le visa                           *
*   rect       : Surface dans laquelle centrer le visa                         *
*   eStdIDVisa : ID du visa standard à dessiner.                               *
*                                                                              *
* Note : La procédure ne réalise aucun clipping pour le dessin du visa.        *
\******************************************************************************/
void __fastcall DrawVisa(TCanvas *pCanvas,const TRect &rect,int eStdIDVisa,bool Stretch)
{
 #ifdef _DEBUG
  if( pCanvas->CopyMode != cmSrcCopy)
    ::MessageBox( 0, "pCanvas->CopyMode != cmSrcCopy", "EIC.cpp::DrawVisa()", MB_ICONWARNING);
 #endif

 if( LoadVisas())
 { // Affichage du visa
   pCanvas->FillRect( rect);               // Effacement de la surface de dessin
   if (Stretch)
    {
      Graphics::TBitmap *Image;
//      TImage *Image;
      int Largeur;
      TRect rect2(rect);
      rect2.Right = rect2.Left + (rect2.Bottom - rect2.Top) * STDIDB_VISAS_WIDTH / STDIDB_VISAS_HEIGHT;
      if (rect2.Right > rect.Right)
        {
          rect2.Right = rect.Right;
          rect2.Bottom = rect2.Top + (rect2.Right - rect2.Left) * STDIDB_VISAS_HEIGHT / STDIDB_VISAS_WIDTH;
          Largeur = (rect.Bottom - rect2.Bottom) / 2;
          rect2.Bottom += Largeur;
          rect2.Top += Largeur;
        }
      else
        {
          Largeur = (rect.Right - rect2.Right) / 2;
          rect2.Right += Largeur;
          rect2.Left += Largeur;
        }
//      Image = new TImage(0);
      Image = new Graphics::TBitmap();
      Image->HandleType = bmDIB;
      Image->Width = STDIDB_VISAS_WIDTH;
      Image->Height = STDIDB_VISAS_HEIGHT;
      _pimglstVisas->Draw(Image->Canvas,0,0,eStdIDVisa,true);
      pCanvas->StretchDraw(rect2,Image/*->Picture->Bitmap*/);
      delete Image;
    }
   else
     if( ( eStdIDVisa >= STDIDB_VISA_FIRST) &&
         ( eStdIDVisa <= STDIDB_VISA_LAST))
     { // Dessin du visa
       // Attention: Le rectangle de cliping du visa ne peut pas être initialisé ici
       // (il faut dériver la grille ou bidouiller le handle windows...)
       _pimglstVisas->Draw( pCanvas,
          ( rect.Left + rect.Right  - STDIDB_VISAS_WIDTH)  / 2,
          ( rect.Top  + rect.Bottom - STDIDB_VISAS_HEIGHT) / 2,
          eStdIDVisa, true);
     }
     else
     { // On ne veut pas dessiner de visa (ce qu'il y avait à la place a été effacé
       #ifdef _DEBUG
        if( eStdIDVisa != STDIDB_VISA_AUCUN)
         ::MessageBox( 0, "ID visa standard invalide...", "EIC.cpp::DrawVisa()", MB_ICONWARNING);
       #endif
     }
 }
}

TList *CSablier::m_ListeCursPrevious = NULL;
unsigned int CSablier::m_nbCSablier = 0;

//****************//
// Class CSablier //
//****************//////////////////////////////////////////////////////////////
//                                                                            //
//   Cette classe permet de gérer le pointeur de la souris pour le transformer//
// en sablier.                                                                //
////////////////////////////////////////////////////////////////////////////////
__fastcall CSablier::CSablier()
{
 if (!m_nbCSablier++)
   m_ListeCursPrevious = new TList();
 m_bWaiting = false;
 Wait();
}



__fastcall CSablier::~CSablier()
{
 Fin();
 if (!--m_nbCSablier)
  {
    delete m_ListeCursPrevious;
    m_ListeCursPrevious = NULL;
  }
}


void __fastcall CSablier::Fin()
{
 if( m_bWaiting)
 {
   Screen->Cursor = (TCursor)m_ListeCursPrevious->Items[m_ListeCursPrevious->Count - 1];
   m_ListeCursPrevious->Delete(m_ListeCursPrevious->Count - 1);
   m_bWaiting     = false;
 }
}



// (Re)positionne le sablier
void __fastcall CSablier::Wait()
{
 if( !m_bWaiting)
 {
   m_ListeCursPrevious->Add((void *)Screen->Cursor);
   m_bWaiting     = true;
 }
 Screen->Cursor = crHourGlass;
}


AnsiString __fastcall EICGetTempFileName()
{
  char szTempPath    [MAX_PATH];
  char szTempFileName[MAX_PATH];

  if( ::GetTempPath( MAX_PATH, szTempPath)==0) throw ELastError( TAG( 51));
  if( ::GetTempFileName( szTempPath, "EIC", 0, szTempFileName)==0) throw ELastError( TAG( 52));

  return AnsiString( szTempFileName);
}


/******************************************************************************\
************* EICDirExist() ****************************************************
********************************************************************************
*                                                                              *
*    Cette fonction permet de savoir si un répertoire existe ou non.           *
*                                                                              *
* Paramètres :                                                                 *
*   strPath       : Chemin à tester et à modifier.                             *
*   bEndBackSlash : TRUE pour ajouter un '\\' final au chemin s'il n'en n'a    *
*                   pas déjà un; FALSE pour ôter l'éventuel '\\' final.        *
*                                                                              *
* Retour :                                                                     *
*   TRUE si le chemin existe; FALSE sinon.                                     *
*                                                                              *
* Note : Le résultat de la fonction est indéterminé avec les chemins "\\" et ""*
\******************************************************************************/
bool __fastcall EICDirExist( AnsiString& strPath,
			     bool        bEndBackSlash) // = true
{
 DWORD dwAttr; // Attributs du chemin
 bool  bExist; // TRUE si le chemin existe


 /////////////////////////
 // Recherche du chemin //
 /////////////////////////
 dwAttr = ::GetFileAttributes( strPath.c_str());
 if( ( dwAttr & ( /*FILE_ATTRIBUTE_READONLY | */FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_OFFLINE)) ||
     !( dwAttr & FILE_ATTRIBUTE_DIRECTORY))
 { // Erreur: ce chemin n'existe pas, n'est pas un répertoire, est en lecture seule ou déconnecté du réseau !
   bExist = false;
 }
 else
   bExist = true;


 //////////////////////////////////////////////
 // Ajout/Retrait du '\\' terminal au chemin //
 //////////////////////////////////////////////
 if( !strPath.IsEmpty())
   if( ( *strPath.AnsiLastChar() == '\\') ^ bEndBackSlash)
     if( bEndBackSlash)
       strPath += "\\";
     else
       strPath.SetLength( strPath.Length() - 1);
 return bExist;
}



bool __fastcall EICLecteurDisponible(const AnsiString& strPath,bool MessageErreur)
{
  AnsiString Lecteur(ExtractFileDrive(strPath));
  int lnResult = SetErrorMode(SEM_FAILCRITICALERRORS);      //Pour éviter d'avoir la fenêtre comme quoi le lecteur n'est pas prêt sous W2K
  bool RepertoireExiste = DirectoryExists(Lecteur);
  lnResult = SetErrorMode(lnResult);
  if (!RepertoireExiste)
    {
      if (MessageErreur)
        EICAttention("Votre lecteur (" + Lecteur + ") est indisponible pour l'instant.");
      return false;
    }
  return true;
}



/******************************************************************************\
************* EICFileExist() ***************************************************
********************************************************************************
*                                                                              *
*    Cette fonction permet de savoir si un fichier existe dans un répertoire.  *
*                                                                              *
* Paramètres :                                                                 *
*   strFilePath    :  Terminé par '\\' = Chemin dans lequel rechercher le(s)   *
*                                        fichier(s) strFilePattern (""=courant)*
*                    !Terminé par '\\' = Nom complet du fichier à rechercher   *
*                                        (jockers non autorisés)               *
*   strFilePattern : Nom du fichier (avec jockers éventuels) à rechercher dans *
*                    le chemin (ignoré si strFilePath est non terminé par '\\')*
*                                                                              *
* Retour :                                                                     *
*   TRUE si le fichier (ou un fichier du pattern) est trouvé, FALSE sinon.     *
\******************************************************************************/
bool __fastcall EICFileExist( const AnsiString& strFilePath,
			      const AnsiString& strFilePattern /* = EmptyStr */)
{
 HANDLE          hFindFile; // Handle de recherche des fichiers du pattern
 WIN32_FIND_DATA ffd;       // Structure pour la recherche de pattern
  if (strFilePath.IsEmpty() && strFilePattern.IsEmpty())
    return false;
 // Si un chemin (terminé par '\\') est précisé, un nom de fichier DOIT être aussi spécifié
 #ifdef _DEBUG
  if( !strFilePath.IsEmpty() && ( *strFilePath.AnsiLastChar() != '\\'))
  { // Il faut rechercher exactement 1 fichier (caractères jockers interdits)
	// => strFilePattern est ignoré
	ASSERT( !strspn( strFilePath.c_str(), "*?")); // Jockers interdits dans le chemin
  }
  else
  { // Il faut rechercher strFileName (avec d'éventuels jockers) dans le chemin spécifié
	// (si le chemin est vide, la recherche a lieu dans le répertoire courant)
	ASSERT( !strspn( strFilePath.c_str(), "*?")); // Jockers interdits dans le chemin
//	ASSERT( !strFilePattern.IsEmpty());           // Nom de fichier(s) obligatoire
  }
 #endif

 if( strFilePath.IsEmpty() || ( *strFilePath.AnsiLastChar() == '\\'))
 { // Nous avons affaire à un chemin
   bool bFound = false;

   ////////////////////////////////////////////////
   // Recherche du/des fichier(s) dans le chemin //
   ////////////////////////////////////////////////
   int lnResult = SetErrorMode(SEM_FAILCRITICALERRORS);      //Pour éviter d'avoir la fenêtre comme quoi le lecteur n'est pas prêt sous W2K
   if( ( hFindFile = ::FindFirstFile( ( strFilePath + strFilePattern).c_str(), &ffd)) != INVALID_HANDLE_VALUE)
   { // Au moins 1 fichier (ou répertoire) du pattern existe
	 do
	 {
	   if( !( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
	   { // Fichier (qui n'est pas un répertoire) trouvé
		 bFound = true;
		 break;
	   }
	 } while( ::FindNextFile( hFindFile, &ffd));
	 ::FindClose( hFindFile);
   }
   lnResult = SetErrorMode(lnResult);
   return bFound;
 }
 else
 { // Nous avons affaire à un nom complet de fichier
   //////////////////////////
   // Recherche du fichier //
   //////////////////////////
   // Si le fichier n'existe pas, ::GetFileAttributes() va retourner 0xFFFFFFFF
   // i.e. FILE_ATTRIBUTE_OFFLINE et FILE_ATTRIBUTE_DIRECTORY seront positionnés
   int lnResult = SetErrorMode(SEM_FAILCRITICALERRORS);      //Pour éviter d'avoir la fenêtre comme quoi le lecteur n'est pas prêt sous W2K
   DWORD Attr = ::GetFileAttributes( strFilePath.c_str());
   lnResult = SetErrorMode(lnResult);
   if ((Attr != 0xFFFFFFFF) && !(Attr & ( FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_DIRECTORY)))
   { // Le fichier a été trouvé
     return true;
   }
 }
 // Aucun fichier trouvé
 return false;
} /* EICFileExist() */



/******************************************************************************\
************* EICDeletePattern() ***********************************************
********************************************************************************
*                                                                              *
*    Cette procédure permet de détruire un ensemble de fichiers dans un        *
* répertoire donné.                                                            *
*                                                                              *
* Paramètres :                                                                 *
*   strFilePath          : Chemin de destruction du pattern (avec ou sans '\\' *
*                          final).                                             *
*   strFilePattern       : Fichiers à détruire (jokers '*' et '?' autorisés)   *
*   bDeleteReadOnlyFiles : TRUE s'il faut aussi détruire les fichiers en       *
*                          en lecture seule.                                   *
\******************************************************************************/
void __fastcall EICDeletePattern( const AnsiString& strFilePath,
				  const AnsiString& strFilePattern,
				  bool              bDeleteReadOnlyFiles /* = false */)
{
 ASSERT( !strFilePath.IsEmpty() && !strFilePattern.IsEmpty());
 ASSERT( !strspn( strFilePath.c_str(), "*?")); // Jockers interdits dans le chemin

 if( strFilePath.IsEmpty() || strFilePattern.IsEmpty())
   EICThrowInvalidArgument( TAG( 10));
 HANDLE          hFindFile;                 // Handle de recherche des fichiers du pattern
 WIN32_FIND_DATA ffd;                       // Structure pour la recherche de pattern
 AnsiString      strFullPath( strFilePath); // Chemin complet des fichiers (avec '\\' terminal)

 if( *strFullPath.AnsiLastChar() != '\\')
   strFullPath += AnsiString( "\\");
 // Destruction des fichiers du pattern //
 if( ( hFindFile = ::FindFirstFile( ( strFullPath + strFilePattern).c_str(), &ffd)) != INVALID_HANDLE_VALUE)
 {
   do
   { // Effacement du fichier du pattern (si le fichier trouvé représente un répertoire - même "." ou "..", il est impossible de le détruire avec cette fonction)
     if( bDeleteReadOnlyFiles && ( ffd.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
       ::SetFileAttributes( ( strFullPath + ffd.cFileName).c_str(), ffd.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);

     ::DeleteFile( ( strFullPath + ffd.cFileName).c_str());
   } while( ::FindNextFile( hFindFile, &ffd));

   ::FindClose( hFindFile);
 }
}


/******************************************************************************\
************* EICEnumPattern() *************************************************
********************************************************************************
*                                                                              *
*    Cette fonction permet d'énumérer des fichiers d'un pattern.               *
*                                                                              *
* Paramètres :                                                                 *
*   strFilePath            : Chemin d'énumération (terminé par '\\')           *
*   strFilePattern         : Fichiers à énumérer (jokers '*' et '?' autorisés) *
*   pfnEnumPatternCallback : Fonction à appeller pour chaque fichier trouvé    *
*                            dans le pattern.                                  *
*   lCallbackUserData      : Valeur utilisateur passée au callback.            *
*                                                                              *
* Retour :                                                                     *
*   Le nb de fichiers enumérés par le callback.                                *
*                                                                              *
* Note : Si le callback lève une exception, l'énumération continue mais la     *
*        fonction retourne -(le nb de fichiers énumérés par le callback).      *
\******************************************************************************/
int __fastcall EICEnumPattern( const AnsiString&    strFilePath,
			       const AnsiString&    strFilePattern,
			       ENUMPATTERN_CALLBACK pfnEnumPatternCallback,
			       long                 lCallbackUserData /* = 0 */)
{
 HANDLE          hFindFile;            // Handle de recherche des fichiers du pattern
 WIN32_FIND_DATA ffd;                  // Structure pour la recherche de pattern
 bool            bContinueEnumeration; // FALSE pour stopper l'énumération
 int             nNbEnumeratedFiles;   // Nb de fichiers énumérés par le callback
 bool            bCallbackException;   // TRUE si une exception est levée dans le callback

 ASSERT( !strFilePath.IsEmpty() && !strFilePattern.IsEmpty());
 ASSERT( *strFilePath.AnsiLastChar() == '\\');
 ASSERT( !strspn( strFilePath.c_str(), "*?")); // Jockers interdits dans le chemin
 ASSERT( pfnEnumPatternCallback);

 if( strFilePath.IsEmpty() || strFilePattern.IsEmpty() || !pfnEnumPatternCallback)
   EICThrowInvalidArgument( TAG( 20));
 // Enumération des fichiers du pattern //
 bCallbackException = false;
 nNbEnumeratedFiles = 0;
 if( ( hFindFile = ::FindFirstFile( ( strFilePath + strFilePattern).c_str(), &ffd)) != INVALID_HANDLE_VALUE)
 {
   bContinueEnumeration = true;
   do
   { // Effacement du fichier du pattern (si le fichier trouvé représente un répertoire - même "." ou "..", il est impossible de le détruire avec cette fonction)
     try {
       pfnEnumPatternCallback( strFilePath + ffd.cFileName, bContinueEnumeration, lCallbackUserData);
     #ifdef _DEBUG
     } catch( Exception& e) {
       // On affiche l'exception du callback pour inforamtion seulement
       EICDisplayExceptionMsg( e, "L'énumération des fichiers va quand même continuer...",
			       AnsiString( "_DEBUG: EICEnumPattern( \"" + strFilePath + "\", \"" + strFilePattern + "\")").c_str());
     #else
     } catch(...) {
       // On ignore toute exception du callback
     #endif
       bCallbackException = true;
     }
     nNbEnumeratedFiles++;
   } while( bContinueEnumeration && ::FindNextFile( hFindFile, &ffd));

   ::FindClose( hFindFile);
 }
 return bCallbackException ? -nNbEnumeratedFiles : nNbEnumeratedFiles;
} /* EICEnumPattern() */


/******************************************************************************\
************* EICCopy() ********************************************************
********************************************************************************
*                                                                              *
*    Cette fonction permet de copier un fichier. Plusieurs options de          *
* traitement peuvent être précisées dans le flag fCopyFlags.                   *
*                                                                              *
* Paramètres :                                                                 *
*   strNomSource : Nom du fichier source à copier.                             *
*   strNomCible  :  "  "     "    cible à créer (comme copie de Source)        *
*   fCopyFlags   : Diverses options de traitement (CF_*)                       *
*                                                                              *
* Retour :                                                                     *
*   Une valeur CF_ERR_* (CF_ERR_OK si le traitement (et ses options) s'est     *
* correctement déroulé).                                                       *
\******************************************************************************/
unsigned __fastcall EICCopy( const AnsiString& strNomSource,
			     const AnsiString& strNomCible,
			     unsigned          fCopyFlags)
{
 #define Abort( eErrCode)     eErr = (eErrCode); goto AbortFunc
 #define AbortCopy( eErrCode) eErr = (eErrCode); goto AbortCopyProcess
 const char*  pcszNomSource; // Nom du fichier source à copier (avec une éventuelle destruction après copie)
 const char*  pcszNomCible;  // Nom du fichier cible à créer/écraser (avec une éventuelle sauvegarde avant copie)
 unsigned     eErr;          // Code retour de la fonction
 int          fhSrc, fhDst;  // Handle des fichiers source et destination
 DWORD        dwSrcSize;     // Taille restante à copier du fichier source
 unsigned int uBufSize;      // Taille allouée du buffer de transfert
 void*        pvBuf = NULL;  // Buffer de transfert
 int          nTmp;          // Variables temporaires

 ASSERT( !strNomSource.IsEmpty() && !strNomCible.IsEmpty());
 ASSERT( ( fCopyFlags & ( CF_NO_OVERWRITE | CF_BACKUP_DEST)) != ( CF_NO_OVERWRITE | CF_BACKUP_DEST));

 // Vérification de la possibilité de l'opération //
 if( !access( pcszNomCible = strNomCible.c_str(), 0))
 { // La destination existe
   if( fCopyFlags & CF_BACKUP_DEST)
   { // Une sauvegarde de la destination est demandée
     // => Vérification de la validité du nom de fichier cible (extension cible à créer != ".BAK")
     if( ( pvBuf = (void*)strrchr( pcszNomCible, '.')) != NULL)
     { // Le fichier cible a une extension
       if( !strnicmp( (char*)pvBuf, ".BAK", 4))
       { // Erreur: la cible a déjà l'extension ".BAK" (on ne peut l'écraser)
	 Abort( CF_ERR_DST_OVERWRITE);
       }

       // Calcul de la longueur du nom de fichier cible sans son extension
       nTmp = (int)((const char*)pvBuf - pcszNomCible);
     }
     else
     { // Fichier cible sans extension
       nTmp = strNomCible.Length();
     }


     //
     // Sauvegarde de la cible (avant de l'écraser par la source)
     //
     if( ( pvBuf = malloc( nTmp + 5)) == NULL)
     { // Mémoire insuffisante
       Abort( CF_ERR_LOW_MEM);
     }

     // Construction du nom du fichier de sauvegarde
     sprintf( (char*)pvBuf, "%.*s.BAK", nTmp, pcszNomCible);

     // Effacement (éventuel) de l'ancienne sauvegarde
     ::DeleteFile( (const char*)pvBuf);

     // MAJ extension cible
     //EICRename( pcszNomCible, pvBuf);

     // Libération ressources
     free( pvBuf); pvBuf = NULL;
   }
   else if( fCopyFlags & CF_NO_OVERWRITE)
   { /* Erreur: la cible existe et ne doit pas être écrasée */
     Abort( CF_ERR_DST_OVERWRITE);
   }
 }

 //
 // Ouverture du fichier source en lecture
 //
 pcszNomSource = strNomSource.c_str();
 if( FileExists( pcszNomSource) && ( ( fhSrc = _rtl_open( pcszNomSource, O_BINARY | O_RDONLY | O_NOINHERIT | SH_DENYWR)) >= 0))
 { // Fichier source correctement ouvert
   if( ( dwSrcSize = (DWORD)filelength( fhSrc)) == 0xFFFFFFFF)//::GetFileSize( (HANDLE)fhSrc, NULL)) == 0xFFFFFFFF)
   { // Source de taille >= 4Go ou lecture de la taille du source impossible
     _rtl_close( fhSrc);
     Abort( CF_ERR_OTHER);
   }
 }
 else
 { // Erreur d'ouverture du fichier source
   switch( (int)errno)
   {
     case ENOENT : Abort( CF_ERR_NO_SRC);
     case EACCES : Abort( CF_ERR_SRC_DENIED);
     default     : Abort( CF_ERR_OTHER);
   }
 }

 //
 // Ouverture du fichier cible en création
 //
// if( ( fhDst = _sopen( pcszNomCible, O_CREAT | O_TRUNC | O_BINARY | O_WRONLY | O_NOINHERIT, SH_DENYRW, S_IREAD | S_IWRITE)) < 0)
 /*if( FileExists( pcszNomCible)) fhDst = _rtl_open(pcszNomCible,O_NOINHERIT | O_WRONLY | O_TRUNC | O_BINARY | SH_DENYRW | O_RDWR);
                           else */
 fhDst = _rtl_creat( pcszNomCible, 0);

 if ( fhDst < 0)
 { // Erreur de création du fichier cible
   nTmp = (int)errno;

   // => Fermeture de la source
   _rtl_close( fhSrc);

   // => Retour sur erreur
   switch( nTmp)
   {
     case EACCES : Abort( CF_ERR_DST_DENIED);
     default     : Abort( CF_ERR_OTHER);
   }
 }


 /////////////////////////////
 // Préparation de la copie //
 /////////////////////////////
 if( dwSrcSize)
 { // Initialisation de la taille du buffer de transfert
   if( dwSrcSize > (DWORD)(UINT_MAX-1))
     uBufSize = (unsigned int)(UINT_MAX-1);
   else
     uBufSize = (unsigned int)dwSrcSize;

   // Allocation (optimale) du buffer de transfert
   for(;;)
   {
     if( ( pvBuf = malloc( uBufSize)) == NULL)
     { // Allocation impossible
       if( uBufSize < 512)
       { // Erreur: Mémoire insuffisante (<512 octets) pour la copie
	 AbortCopy( CF_ERR_LOW_MEM);
       }
       else
       { // Division par 2 de la taille du buffer de transfert
	 uBufSize >>= 1;
       }
     }
     else
     { // Allocation réussie
       break;
     }
   }
 }
 else
 { // Fichier source de taille nulle
   uBufSize = 0;
   pvBuf    = NULL;
 }


 ///////////
 // Copie //
 ///////////
 while( uBufSize)
 {
   ASSERT( dwSrcSize > 0L);
   ASSERT( dwSrcSize >= (DWORD)uBufSize);
   ASSERT( (int)uBufSize != -1);

   if( _rtl_read( fhSrc, pvBuf, uBufSize) == (int)uBufSize)
   { // Lecture d'un bloc Ok
     if( _rtl_write( fhDst, pvBuf, uBufSize) == (int)uBufSize)
     { // Ecriture du bloc Ok

       // => MAJ de la taille restante à copier
       if( ( dwSrcSize -= (DWORD)uBufSize) < (DWORD)uBufSize)
       {
	 uBufSize = (unsigned int)dwSrcSize;
       }
     }
     else
     { // Erreur d'écriture dans Dst
       AbortCopy( CF_ERR_WR_DST);
     }
   }
   else
   { // Pb de lecture du source
     AbortCopy( CF_ERR_RD_SRC);
   }
 }


 ////////////////////////////
 // Fermeture des fichiers //
 ////////////////////////////
 if( _rtl_close( fhSrc))
 { // Erreur de fermeture du source
   AbortCopy( CF_ERR_RD_SRC);
 }

 if( _rtl_close( fhDst))
 { // Erreur de fermeture de la cible
   eErr = CF_ERR_WR_DST;
AbortCopyProcess:
   _rtl_close( fhSrc);
   _rtl_close( fhDst);
 }
 else
 { // Pas d'erreur
   eErr = CF_ERR_OK;

   ///////////////////////////////////
   // Destruction du fichier source //
   ///////////////////////////////////
   if( fCopyFlags & CF_DEL_SOURCE)
   {
     ::DeleteFile( pcszNomSource);
   }
 }
 if( pvBuf) { free( pvBuf); pvBuf = NULL; }
AbortFunc:
 if( ( eErr != CF_ERR_OK) && ( fCopyFlags & CF_AFF_ERROR))
 { /* Affichage de l'erreur */
   switch( eErr)
   { case CF_ERR_DST_OVERWRITE : pvBuf = "Fichier cible \"%s\" déjà existant.";                  break;
     case CF_ERR_NO_SRC        : pvBuf = "Fichier source \"%s\" non trouvé.";                    break;
     case CF_ERR_SRC_DENIED    : pvBuf = "Lecture du fichier source \"%s\" refusée.";            break;
     case CF_ERR_DST_DENIED    : pvBuf = "Ecriture du fichier cible \"%s\" refusée.";            break;
     case CF_ERR_LOW_MEM       : pvBuf = "Mémoire insuffisante pour copier \"%s\" vers \"%s\"."; break;
     case CF_ERR_RD_SRC        : pvBuf = "Erreur de lecture du fichier source \"%s\".";          break;
     case CF_ERR_WR_DST        : pvBuf = "Erreur d'écriture du fichier cible \"%s\".";           break;
     default                   : ASSERT( eErr == CF_ERR_OTHER);
				 pvBuf = "Erreur inconnue en copiant \"%s\" vers \"%s\".";       break;
   }
   EICErreur( EICFormat( (const char*)pvBuf,
			 ( eErr & ( CF_ERR_DST_OVERWRITE | CF_ERR_DST_DENIED | CF_ERR_WR_DST)) ? pcszNomCible : pcszNomSource,
			 pcszNomCible).c_str());
 }
 return eErr;

 #undef AbortCopy
 #undef Abort
} /* EICCopy() */



/******************************************************************************\
************* EICTagToStr() ****************************************************
********************************************************************************
*                                                                              *
*    Cette fonction retourne un tag d'opération sous forme lisible (attention: *
* le module d'origine n'est pas inclus dans l'expression lisible du tag).      *
*                                                                              *
* Paramètres :                                                                 *
*   tag : Tag à convertir en une chaîne lisible ("CodeModule-CodeOpération")   *
*                                                                              *
* Retour :                                                                     *
*   Le Tag sous forme lisible.                                                 *
\******************************************************************************/
AnsiString __fastcall EICTagToStr( EICTag tag)
{
 char szTmp[ 15];

 sprintf( szTmp, "%hu-%hu", TAG_MODULE( tag), TAG_TAG( tag)); ASSERT_VALID_STRING( szTmp);
 return AnsiString( szTmp);
}


/******************************************************************************\
************* EICThrowInvalidArgument() ****************************************
********************************************************************************
*                                                                              *
*    Cette procédure permet de générer une exception EInvalidArgument          *
* personnalisée (i.e. décorée d'une origine et avec un message personnalisé).  *
*                                                                              *
* Paramètres :                                                                 *
*   tag       : Tag de l'opération                                             *
*   idsErr    : ID de la chaîne de ressources du message de l'exception.       *
*   hInstance : Instance du module qui veut lever l'exception.                 *
\******************************************************************************/
void __fastcall EICThrowInvalidArgument( EICTag tag,
					 int    idsErr    /* = IDS_EXCEPTION_INVALID_ARGUMENT */,
					 void*  hInstance /* = HInstance */)
{
 char szModulePath[ _MAX_PATH + 1];

 throw EInvalidArgument( EICFormat( "%s (%s): %s",
					 ModuleShortName( hInstance, szModulePath),
					 EICTagToStr( tag).c_str(),
					 EICResStr( idsErr).c_str()));
}
void __fastcall EICThrowInvalidArgument(EICTag tag,const AnsiString &Texte,void*  hInstance)
{
 char szModulePath[ _MAX_PATH + 1];
 throw EInvalidArgument( EICFormat( "%s (%s): %s",
					 ModuleShortName( hInstance, szModulePath),
					 EICTagToStr( tag).c_str(),
					 Texte.c_str()));
}


// Désactive les messages "Non-const function _fastcall System::TObject::InheritsFrom(System::TMetaClass*)/System::TObject::ClassName() called for const object."
#pragma warn -ncf
__fastcall EUser::EUser( EICTag tag, const Exception& e, int hInstance /* = (int)HInstance */)
: Exception( e.Message), m_hInstance( (void*)hInstance)
{
 if( e.InheritsFrom( __classid( EUser)))
 {
   m_strOrigine = EICTagToStr( tag) +
		  + ", " +
		  DecorateOrigin( (void*)hInstance, (const EUser&)e);
 }
 else
   m_strOrigine = EICTagToStr( tag) + ":" + e.ClassName();
}
// Réactive les messages "Non-const function ? called for const object."
#pragma warn .ncf


__fastcall EUser::EUser( EICTag            tag,
			 const AnsiString& strMsg,
			 int               hInstance /* = (int)HInstance */)
: Exception( strMsg), m_hInstance( (void*)hInstance), m_strOrigine( EICTagToStr( tag))
{
}

__fastcall EUser::EUser( EICTag      tag,
			 const char* pcszIDSMsg, /* MAKEINTRESOURCE accepté */
			 int         hInstance /* = (int)HInstance */)
: Exception( EICResStr( pcszIDSMsg)), m_hInstance( (void*)hInstance), m_strOrigine( EICTagToStr( tag))
{
}

AnsiString __fastcall ELastError::GetSysErrorMsg( DWORD dwSysErrorCode)
{
 LPVOID lpvMsg;     // Message système de traduction du code erreur
 char   szTmp[ 50]; // Variable temporaire


 /////////////////////////////////////////
 // Conversion du code (en héxadécimal) //
 /////////////////////////////////////////
 sprintf( szTmp, " (%#x \"", dwSysErrorCode); ASSERT_VALID_STRING( szTmp);
 AnsiString strErrMsg( szTmp);


 ///////////////////////////////////////////////
 // Ajout du message d'erreur système au code //
 ///////////////////////////////////////////////
 lpvMsg = NULL;
 strErrMsg += AnsiString( (const char*)( ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL,
							  dwSysErrorCode, 0,
							  (LPSTR)&lpvMsg, 0, NULL) ? lpvMsg : "\?\?\?"));
 ::LocalFree( lpvMsg);
 return strErrMsg + "\")";
}



__fastcall ELastError::ELastError( EICTag            tag,
				   const AnsiString& strMsg,
				   int               hInstance /* = (int)HInstance */)
: EUser( tag, strMsg, hInstance)
{
 AddLastErrorToOrigine();
}



__fastcall ELastError::ELastError( EICTag      tag,
				   const char* pcszIDSMsg,
				   int         hInstance /* = (int)HInstance */)
: EUser( tag, pcszIDSMsg, hInstance)
{
 AddLastErrorToOrigine();
} /* ELastError::ELastError() */



void __fastcall ELastError::AddLastErrorToOrigine()
{
 ///////////////////////////////////////////////////////////////
 // Ajout du message d'erreur système à l'origine de l'erreur //
 ///////////////////////////////////////////////////////////////
 m_strOrigine += GetSysErrorMsg( ::GetLastError());
}

static
unsigned short __fastcall _GetDernierJourMois( unsigned short ushMois,
					       unsigned short ushAnnee)
{
 static unsigned char ucLastDays[ 12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

 ASSERT( ( ushMois >= 1) && ( ushMois <= 12));

 return (unsigned short)( ( ( ushMois == 2) && IsBissextile( ushAnnee)) ? 29 : ucLastDays[ ushMois - 1]);
}

/******************************************************************************\
************* DiffDateMois() ***************************************************
********************************************************************************
*                                                                              *
*    Cette fonction retourne le nb de mois calendaires qui séparent deux dates.*
*                                                                              *
* Paramètres :                                                                 *
*   dtMin, dtMax : Dates à comparer.                                           *
*                                                                              *
* Retour :                                                                     *
*   Le nombre de mois entiers - positif ou négatif - qui séparent 2 dates.     *
*                                                                              *
* Exemples :                                                                   *
*  ( 05/04/98, 23/04/98) =  0;  ( 01/01/98, 31/01/98) =  0;                    *
*  ( 05/04/98, 01/05/98) =  1;  ( 01/05/98, 05/04/98) = -1;                    *
*  ( 01/01/98, 31/12/98) = 12;  ( 01/01/98, 01/12/98) = 12;                    *
\******************************************************************************/
int __fastcall DiffDateMois( const TDateTime& dtMin,
			     const TDateTime& dtMax)
{
 unsigned short ushAnnee1, ushMois1, ushAnnee2, ushMois2, ushJour;

 dtMin.DecodeDate( &ushAnnee1, &ushMois1, &ushJour);
 dtMax.DecodeDate( &ushAnnee2, &ushMois2, &ushJour);



 return ( ushAnnee2 - ushAnnee1) * 12 + ushMois2 - ushMois1;
}
/********************************************************************************
*                                                                              *
*    Cette fonction retourne le nb de mois calendaires qui séparent deux dates.*
*                                                                              *
* Paramètres :                                                                 *
*   2 Dates à comparer.                                                        *
*                                                                              *
* Retour :                                                                     *
*   Le nombre de mois entiers positif qui séparent 2 dates.                    *
*                                                                              *
*                                                                              *
\******************************************************************************/

int __fastcall DiffDateNbMois( const TDateTime &dtDate1 , const TDateTime &dtDate2)
{
    unsigned short usAnneeMax, usMoisMax, usJourMax,usAnneeMin, usMoisMin, usJourMin;
    TDateTime dtDateMax, dtDateMin;
    int nbAnnee, nbMois;

    try {
        if (dtDate1 == dtDate2) return 0;
        dtDateMax = (dtDate1 > dtDate2) ? dtDate1 : dtDate2;
        dtDateMin  = (dtDate1 < dtDate2) ? dtDate1 : dtDate2;
        dtDateMax.DecodeDate(&usAnneeMax, &usMoisMax, &usJourMax);
        dtDateMin.DecodeDate(&usAnneeMin, &usMoisMin, &usJourMin);

        nbAnnee = usAnneeMax - usAnneeMin;
        nbMois = usMoisMax - usMoisMin;

        if (usMoisMax<usMoisMin) {
            nbAnnee -= 1;
            nbMois = 12 - usMoisMin + usMoisMax;
        }

        if (usMoisMax!=usMoisMin) {
            if (usJourMax<usJourMin)            nbMois -=1;
            else if ( usJourMax > usJourMin)    nbMois +=1;
        }

    }
    catch(Exception &e) {
        ShowMessage(e.Message);
        return -1;
    }
    return( (nbAnnee * 12) + nbMois );

}
/**************************************************************
* Calcule la diff‚rence exacte de jours entre 2 dates (d2-d1) *
* Les bornes sont comprises. d2 doit ˆtre sup‚rieure … d1.    *
* Calcule la diff‚rence de jours entre 2 dates (d2-d1) … la mode URSSAF : *
*  - les ann‚es entiŠres font 360 jours                                   *
*  - les mois entiers font 30 jours                                       *
**************************************************************/
int        __fastcall DiffDateJours( const TDateTime& dtMin, const TDateTime& dtMax, bool EnMoisDe30Jours)
{
    if( EnMoisDe30Jours)
    {
        TDateTime d, d1 = min( dtMin, dtMax), 
                     d2 = max( dtMin, dtMax);

        int ret;
    	unsigned short shYear1, shMonth1, shDay1, shYear2, shMonth2, shDay2, shDernJourMois2;
        d = d2;
	    DernierJourMois(d);
        d.DecodeDate( &shYear2, &shMonth2, &shDernJourMois2);

        d1.DecodeDate( &shYear1, &shMonth1, &shDay1);
        d2.DecodeDate( &shYear2, &shMonth2, &shDay2);
         /*** Ann‚es entiŠres = 360 jours ***/
        ret = 360 * max(0, shYear2 - shYear1 - 1);
         /*** Mois entiers = 30 jours ***/
        ret += 30 * ((shYear1 == shYear2) ? max( 0, shMonth2 - shMonth1 - 1) : ( 12 + shMonth2 - shMonth1 - 1));
         /*** Jours restants ***/                                                                               /* min(30,d2->j)       anciennement       */
        ret += ((shYear1 == shYear2) && (shMonth1 == shMonth2)) ?
                    min( 30, min( 30, (int)shDay2) - shDay1 + 1)
                :   30 - (shDay1 - 1) + ((shDay2 == shDernJourMois2) ? (USHORT)30 : shDay2);
        if (dtMin > dtMax)
            ret *= -1;
        return ret;
    }
    return  max( 0, int(dtMax) - int(dtMin) +1 );
}

/******************************************************************************\
************* DernierJourMois() ************************************************
********************************************************************************
*                                                                              *
*    Cette fonction positionne le mois d'une date à son dernier jour.          *
*                                                                              *
* Paramètres :                                                                 *
*   dt : Date dont on veut positionner le jour au dernier jour du mois.        *
*                                                                              *
* Retour :                                                                     *
*   La date passée en paramètre et modifiée.                                   *
\******************************************************************************/
TDateTime& __fastcall DernierJourMois( TDateTime& dt)
{
 unsigned short ushAnnee, ushMois, ushJour;

 dt.DecodeDate( &ushAnnee, &ushMois, &ushJour);
 ASSERT( ushJour <= _GetDernierJourMois( ushMois, ushAnnee));
 return dt += (int)( _GetDernierJourMois( ushMois, ushAnnee) - ushJour);
}
//---------------------------------------------------------------------------
TDateTime __fastcall PremierJourDuMois( const TDateTime &dt)
{
    USHORT  Year, Month, Day;
    dt.DecodeDate(  &Year, &Month, &Day);
    return TDateTime( Year, Month, 1);
}



/******************************************************************************\
************* AjouteMois() *****************************************************
********************************************************************************
*                                                                              *
*    Cette fonction ajoute - ou retranche - un nombre de mois à une date en    *
* respectant les fins de mois (i.e. si la date d'origine est une date de fin   *
* de mois, la date et son nombre de mois en plus - ou en moins - sera une date *
* de fin de mois).                                                             *
*                                                                              *
* Paramètres :                                                                 *
*   dt      : Date à laquelle ajouter - ou retrancher - un nombre de mois.     *
*   nNbMois : >= 0 : Nombre de mois à  ajouter   à la date                     *
*              < 0 :   "    "   "   " retrancher " "   "                       *
*                                                                              *
* Retour :                                                                     *
*   La date modifiée (avec respect des fins de mois).                          *
\******************************************************************************/
TDateTime& __fastcall AjouteMois( TDateTime& dt,
				  int        nNbMois)
{
 unsigned short ushAnnee, ushMois, ushJour; // Composantes des calculs
 unsigned short ushDJM;                     // Dernier jour du mois de la date résultante
 bool           bFinDeMois;                 // TRUE si la date passée en paramètre est une date de fin de mois
 dt.DecodeDate( &ushAnnee, &ushMois, &ushJour);
 bFinDeMois = ( ushJour >= _GetDernierJourMois( ushMois, ushAnnee));
 ////////////////////
 // Ajout des mois //
 ////////////////////
 if( ( nNbMois += ushMois) <= 0)
   // On retranche les années
   do
     ushAnnee--;
   while( ( nNbMois += 12) <= 0);
 else
   // On ajoute les années
   while( nNbMois > 12)
   {
     ushAnnee++;
     nNbMois -= 12;
   }
 // Ici, le mois final est la valeur de nNbMois
 ASSERT( ( nNbMois >= 1) && ( nNbMois <= 12));

 ushDJM = _GetDernierJourMois( (unsigned short)nNbMois, ushAnnee);
 return dt = EncodeDate( ushAnnee, (unsigned short)nNbMois,
			  ( bFinDeMois || ( ushJour > ushDJM)) ? ushDJM : ushJour);
}


/******************************************************************************\
************* AjouteMois() *****************************************************
********************************************************************************
*                                                                              *
*    Cette fonction ajoute - ou retranche - un nombre de mois à une date en    *
* respectant les fins de mois (i.e. si la date d'origine est une date de fin   *
* de mois, la date et son nombre de mois en plus - ou en moins - sera une date *
* de fin de mois) et retourne la date résultante.                              *
*                                                                              *
* Paramètres :                                                                 *
*   dt      : Date à laquelle ajouter - ou retrancher - un nombre de mois.     *
*   nNbMois : >= 0 : Nombre de mois à  ajouter   à la date                     *
*              < 0 :   "    "   "   " retrancher " "   "                       *
*                                                                              *
* Retour :                                                                     *
*   Le calcul de la nouvelle date (avec respect des fins de mois).             *
\******************************************************************************/
TDateTime __fastcall AjouteMois( const TDateTime& dt,
				 int              nNbMois)
{
 TDateTime dtTmp( dt);

 AjouteMois( dtTmp, nNbMois);
 return dtTmp;
}



TDateTime __fastcall AjouteAnnees(const TDateTime &dt,int nNbAnnees)
{
  unsigned short J,M,A;
  dt.DecodeDate(&A,&M,&J);
  A += nNbAnnees;
  if ((M == 2) && ((J == 28) || (J == 29)))
    if (IsLeapYear(A))
      J = 29;
    else
      J = 28;
  return TDateTime(A,M,J);
}



/******************************************************************************\
************* ReadLine() *******************************************************
********************************************************************************
*                                                                              *
*    Cette fonction lit une ligne dans un fichier texte.                       *
*                                                                              *
* Paramètre :   &s : chaine lue.                                               *
* Retour :      Renvoi si on a pu lire une ligne.                              *
\******************************************************************************/
bool __fastcall CTextFileStream::ReadLine( AnsiString &s)
{
	char sz[2] = "\x00\x00",cCR,cLF,Ancien_sz;
	int  nOctetsLus;
	s = EmptyStr;
	nOctetsLus = Read( sz, 1);

  cLF = '\r';
  cCR = '\n';

	if( !nOctetsLus)
	   return false;

	while( (nOctetsLus == 1) && (sz[0] != cCR) && (sz[0] != cLF) )
	{
		s += sz;
		nOctetsLus = Read( sz, 1);
	}
    if( (sz[0] == cCR) || (sz[0] == cLF) )
    {
      Ancien_sz = sz[0];
      if( (Read( sz, 1) == 1) && (!(((sz[0] == cCR) || (sz[0] == cLF)) && (sz[0] != Ancien_sz) )))
        Position --;
	    if( bReadAntiSlash )
        s += cLF;
    }


	return true;
}



/******************************************************************************\
************* WriteLine() ******************************************************
********************************************************************************
*                                                                              *
*    Cette fonction écrit une ligne dans un fichier texte en lui ajoutant un   *
*  '\n' à la fin                                                               *
*                                                                              *
* Paramètre :   &s : chaine lue.                                               *
* Retour :      Renvoi si l'écriture s'est bien passée.                        *
\******************************************************************************/
bool __fastcall CTextFileStream::WriteLine( const AnsiString &s)
{
	try
	{
		Write( s.c_str(), s.Length());

		if( bAddAntiSlash)
		   Write( "\r\n", 2);
	}
	catch( ...)
	{
		return false;
	}
	return true;
}



AnsiString __fastcall OemToChar(const char* pcszOem)
{
  AnsiString str(pcszOem);
  char *s = str.c_str();
  ::OemToChar(s,s);
  return str;
}



AnsiString& __fastcall AnsiOEM(AnsiString& strAnsiDst,const char *pcszOEMSrc,DWORD dwDstMaxSzLen)
{
  DWORD nbChar = min( (DWORD)strlen( pcszOEMSrc), dwDstMaxSzLen);
  char* psz;
  psz = NULL;
  ::OemToCharBuff(pcszOEMSrc,psz = new char[nbChar + 1],nbChar);
  psz[nbChar] = '\0';
  strAnsiDst = psz;
  delete[] psz;
  return strAnsiDst;
}



const char *__fastcall OEMAnsi(char *pszOEMDst,const AnsiString &strAnsiSrc,DWORD dwDstMaxSzLen)
{
  DWORD nbChar = min( (DWORD)strAnsiSrc.Length(), dwDstMaxSzLen);
  ::CharToOemBuff(strAnsiSrc.c_str(),pszOEMDst,nbChar);
  pszOEMDst[nbChar] = '\0';
  return pszOEMDst;
}




////////////////////////////////////////////////////////////////////////////////
//                              Informations / version des Exe, DLL, BPL                                          //
//                                                                                                                                                        //
// P.E.:        Nom complet du fichier                                                                                    //
//                      Un pointeur sur une TStringList qui contiendra les Infos                  //
////////////////////////////////////////////////////////////////////////////////
#define SWAPWORDS(X) ( (X<<16) | (X>>16) )
void __fastcall GetFileVersionInfos( const AnsiString &FullFileName, TStringList *LInfos )
	{        
	DWORD                           HeaderFileSize;
	DWORD                           lpdwHandle;
	unsigned int                    dwLen, uTranLen;
	char                            pszBuffer[4096], szLang[ 255];
	void                            *pvValue;
	VS_FIXEDFILEINFO                *sFixedFileInfo;
	AnsiString                      aConstruct;
	TStringList                     *LKeys = NULL;
    __int64                         li;
    LPDWORD                         lpdwLangCp;

	ASSERT( LInfos );
	ASSERT( !FullFileName.IsEmpty());

	try
		{
		if( access( FullFileName.c_str(), 0 ))
			{
			EICErreur("Fichier "+FullFileName+" inexistant");
			return;
			}

		LKeys = new TStringList();
		LKeys->Add( _KEY_COMPANYNAME            );
		LKeys->Add( _KEY_FILEDESCRIPTION        );
		LKeys->Add( _KEY_FILEVERSION            );
		LKeys->Add( _KEY_ASSEMBLYVERSION        );
		LKeys->Add( _KEY_INTERNALNAME           );
		LKeys->Add( _KEY_LEGALCOPYRIGHT         );
		LKeys->Add( _KEY_LEGALTRADEMARKS        );
		LKeys->Add( _KEY_ORIGINALFILENAME       );
		LKeys->Add( _KEY_PRODUCTNAME            );
		LKeys->Add( _KEY_PRODUCTVERSION         );
		LKeys->Add( _KEY_COMMENTS                       );

		HeaderFileSize = GetFileVersionInfoSize( FullFileName.c_str(), &lpdwHandle );

		if( HeaderFileSize )
			{
			GetFileVersionInfo( FullFileName.c_str(), NULL, HeaderFileSize, pszBuffer );

			VerQueryValue( &pszBuffer, TEXT("\\") ,&pvValue, &dwLen );
			sFixedFileInfo  = (VS_FIXEDFILEINFO*)pvValue;

/*			switch( sFixedFileInfo->dwFileFlags )
				{
				case VS_FF_DEBUG:                       aConstruct = "Débug";           break;
				case VS_FF_PRERELEASE:          aConstruct = "PréVersion";      break;
				case VS_FF_SPECIALBUILD:        aConstruct = "Spéciale";        break;
				case VS_FF_PATCHED:             aConstruct = "DLL";             break;
				case VS_FF_PRIVATEBUILD:        aConstruct = "Privée";          break;
				}*/
      if (sFixedFileInfo->dwFileFlags & VS_FF_DEBUG)
        aConstruct = "Débug";
      else
        aConstruct = EmptyStr;
      if (sFixedFileInfo->dwFileFlags & VS_FF_PRERELEASE)
        {
          if (!aConstruct.IsEmpty())
            aConstruct += "/";
          aConstruct += "PréVersion";
        }
      if (sFixedFileInfo->dwFileFlags & VS_FF_SPECIALBUILD)
        {
          if (!aConstruct.IsEmpty())
            aConstruct += "/";
          aConstruct += "Spéciale";
        }
      if (sFixedFileInfo->dwFileFlags & VS_FF_PATCHED)
        {
          if (!aConstruct.IsEmpty())
            aConstruct += "/";
          aConstruct += "DLL";
        }
      if (sFixedFileInfo->dwFileFlags & VS_FF_PRIVATEBUILD)
        {
          if (!aConstruct.IsEmpty())
            aConstruct += "/";
          aConstruct += "Privée";
        }
			LInfos->Add( AnsiString( "Construction module=" ) + aConstruct );

            li = (((__int64)sFixedFileInfo->dwFileVersionMS) <<32) + sFixedFileInfo->dwFileVersionLS;
    		LInfos->Add( AnsiString(  ).sprintf( "FileVersionNum=%Ld", li));
            li = (((__int64)sFixedFileInfo->dwProductVersionMS) <<32) + sFixedFileInfo->dwProductVersionLS;
    		LInfos->Add( AnsiString(  ).sprintf( "FileProductNum=%Ld", li));


            if( VerQueryValue( &pszBuffer, "\\VarFileInfo\\Translation",
                  (void **) &lpdwLangCp, &uTranLen ) )
            {
                for ( int iIndex = 0; iIndex < (int)( uTranLen / sizeof(void*) );
                      iIndex++ )
                {
                       // Flip the words to display lang first.
//                   if( LOWORD( *(lpdwLangCp + iIndex)) == 0x040C) // Si c'est francais
                   {
                       VerLanguageName( LOWORD( *(lpdwLangCp + iIndex)), szLang, sizeof( szLang));
                       LInfos->Add( AnsiString( "Langue=") + szLang);

                       wsprintf( szLang, "%08X", SWAPWORDS( *(lpdwLangCp + iIndex) ) );

            			for( int i = 0; i < LKeys->Count; i++ )
		                {
            				if( VerQueryValue( &pszBuffer, TEXT(AnsiString(AnsiString("\\StringFileInfo\\")+szLang+/*040C04E4*/"\\" + LKeys->Strings[i]).c_str()),&pvValue, &dwLen ))
    		            		LInfos->Add( LKeys->Strings[i] + "=" + AnsiString( (char*)pvValue ));
            			}
                   }
               }
            }

/*			while( i < LKeys->Count )
				{
				VerQueryValue( &pszBuffer, TEXT(AnsiString(AnsiString("\\StringFileInfo\\040C04E4\\") + LKeys->Strings[i]).c_str()),&pvValue, &dwLen );
				LInfos->Add( LKeys->Strings[i] + "=" + AnsiString( (char*)pvValue ));
				i ++;
				}*/
			}
		}

	catch( Exception &e )
		{
		EICDisplayException( TAG(30), e );
		}
    delete LKeys;
	}

/*******************************************************************************
AnsiString __fastcall GetDLLVer(const AnsiString &aDLLName)

Fonction : Retourne la version chaîne d'une DLL ou d'un exécutable

P.E : aDLLName : Nom de la DLL à analyser

P.S : Retourne VER_DLL_INCONNUE si la version n'a pas été trouvée
*******************************************************************************/
AnsiString __fastcall GetDLLVer(const AnsiString &aDLLName)
	{
	TStringList *LInfos = NULL;
	AnsiString	aNumVer;
   int i = 0;

	try
		{
		LInfos 						= new TStringList();

      GetFileVersionInfos( aDLLName, LInfos );

      //Recherche la chaine contenant le N° de version du fichier
      while ((i < LInfos->Count) && (LInfos->Strings[i].Pos (AnsiString(_KEY_FILEVERSION)+"=")==0))
         i++;

      if ((i != LInfos->Count) && (0 != LInfos->Strings[i].Pos (AnsiString(_KEY_FILEVERSION)+"="))) //Si la chaine est trouvée
         aNumVer 				= EXTRAIRE_CH (LInfos->Strings[i], LInfos->Strings[i].Pos("=") + 1, LInfos->Strings[i].Length());
      else
         aNumVer				= VER_DLL_INCONNUE;
		}

	catch( Exception &e )
		{
		EICDisplayException( TAG(40), e );
		}

	delete LInfos;

	return( aNumVer );
	}

/*******************************************************************************
__int64 __fastcall GetNumeriqueDLLVer(const AnsiString &aDLLName )

Fonction : Retourne la version numérique d'une DLL ou d'un exécutable.
      Le premier et second octets contiennent la version Majeur
      Le troisième et le quatrième contiennent la version Mineur
      Le cinquième et le sixième contiennent la version Sous-version
      Le septième et le huitième contiennent la version Construction

P.E : aDLLName : Nom de la DLL à analyser

P.S : Retourne -1 si la version n'a pas été trouvée
*******************************************************************************/
__int64 __fastcall GetNumeriqueDLLVer(const AnsiString &aDLLName)
	{
	TStringList *LInfos = NULL;
	__int64	iNumVer;
   int i = 0;

	try
		{
		LInfos 						= new TStringList();

      GetFileVersionInfos(aDLLName, LInfos);

      //Recherche la chaîne contenant le N° de version du fichier
      while ((i < LInfos->Count) && (LInfos->Strings[i].Pos ("FileVersionNum=")==0))
         i++;

      if (i < LInfos->Count)
         iNumVer 				= _atoi64(EXTRAIRE_CH (LInfos->Strings[i], LInfos->Strings[i].Pos("=") + 1, LInfos->Strings[i].Length()).c_str());
      else
         iNumVer				= -1;
		}

	catch( Exception &e )
		{
		EICDisplayException( TAG(50), e );
		}

	delete LInfos;

	return iNumVer;
	}
/******************************************************************************\
************* GetFloatDecimalSeparator() ***************************************
********************************************************************************
*                                                                              *
*    Cette fonction retourne le séparateur décimale pour les nombres à virgule.*
*    Cette fonction a été essentiellement créer pour les besoins sous          *
*    ReportMaker.                                                              *
*                                                                              *
\******************************************************************************/
//---------------------------------------------------------------------------
/*
AnsiString __fastcall GetFloatDecimalSeparator( const AnsiString &strDefaut)
{
  // Recherche la version de l'OS sous lequel Menufed est exécuté
  // Si Windows 95 OSR1 OSR2 98 : le séparateur décimale se trouve dans le
  //                              fichier WIN.INI [Intl]sDecimal
  // Si Windows NR              : le séparateur décimale se trouve dans la
  //                              base de registre à l'endroit
  //                              HKEY_CURRENT_USER\Control Panel\International\sDecimal
  AnsiString    strSeparator;
  OSVERSIONINFO osversioninfo;
  osversioninfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO);
  if ( !::GetVersionEx( &osversioninfo)) return strDefaut;

	 if ( osversioninfo.dwPlatformId==VER_PLATFORM_WIN32_NT) {
    // Recherche du séparateur sous NT
    TRegistry *registry = new TRegistry();
    registry->RootKey = HKEY_CURRENT_USER;
    if ( registry->OpenKey( "Control Panel\\International", false)) {
      strSeparator = registry->ReadString( "sDecimal");
      registry->CloseKey();
    } else strSeparator = strDefaut;
    delete registry;
  } else if ( osversioninfo.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS) {
    // Recherche du séparateur sous 95, 98
    TIniFile *wininiFile = new TIniFile( "WIN.INI");
    strSeparator = wininiFile->ReadString( "intl", "sDecimal", strDefaut);
    delete wininiFile;
  } else { ASSERT( false); strSeparator = strDefaut; }

  return strSeparator;
}
*/


//------------------------------------------------------------------------------
void __fastcall DrawGridArrowUpDown( TCanvas *pCanvas, const TRect &rect, int nIDImg)
{
  if( !_pbmpArrow[0] || !_pbmpArrow[1]) {
    _pbmpArrow[0] = new Graphics::TBitmap();
    _pbmpArrow[1] = new Graphics::TBitmap();
    _pbmpArrow[0]->LoadFromResourceName(( int)HInstance, "DOWN");
    _pbmpArrow[1]->LoadFromResourceName(( int)HInstance, "UP"  );
    _pbmpArrow[0]->Transparent = true;
    _pbmpArrow[1]->Transparent = true;
  }

  pCanvas->Draw( rect.Right - _pbmpArrow[nIDImg]->Width - 2,
                 rect.Top   + ( rect.Bottom - rect.Top - _pbmpArrow[nIDImg]->Height) / 2,
                 _pbmpArrow[nIDImg]);
}
//------------------------------------------------------------------------------

/******************************************************************************\
************* CInitEICPackage() ************************************************
********************************************************************************
*                                                                              *
*    Cette fonction permet d'initialiser le paquet EIC                         *
*       - Initialisation du mulot à roue
*                                                                              *
\******************************************************************************/
//------------------------------------------------------------------------------
//unsigned int _WM_MOUSEWHEEL;      // numero du message du mulot à roue
//unsigned int _WHEELSUPPORT;       // mulot à roue supporté
//unsigned int _WHEELSCROLLLINES;   // nb de lignes a scroller lors d'une rotation
//	BOOL _b3DSupport;         // contains returned flag for wheel support active
//	 int _nScrollLines;       // contains returned scroll lines
//HWND         _hwndMsWheelWindow;  // Handle de la fenêtre du mulot à roue
enum CodesPartenaires _CodePartenaire = ecp_EIC;
CODE_PAYS    _CodePays;           // code du pays
bool         _MoveFile;           // voir eic.h
bool         _SignatureElectronique = false;
AnsiString   _ComputerName;       // Nom de la machine
HWND hwndFenetreEICShell = 0;
//------------------------------------------------------------------------------
class CInitEICPackage
{
  public :
    __fastcall  CInitEICPackage(void);
    virtual __fastcall ~CInitEICPackage(void);
};
//------------------------------------------------------------------------------
__fastcall CInitEICPackage::CInitEICPackage()
{
  TRegistry *BaseDeRegistre = 0;
 /////////////////////////////////////////////////////////
 // Initialisation pour le type de la platforme Windows //
 /////////////////////////////////////////////////////////
 OSVERSIONINFO pOsVersionInfo;
	       pOsVersionInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO);
 ::GetVersionEx( &pOsVersionInfo);
 ASSERT( pOsVersionInfo.dwPlatformId!=VER_PLATFORM_WIN32s); // Assert qui ne sert à rien
 _WINPLATFORM = pOsVersionInfo.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS  ? VP_WINDOWS_95_98 :
		pOsVersionInfo.dwPlatformId==VER_PLATFORM_WIN32_NT       ? VP_WINDOWS_NT    : VP_UNKNOWN;
 ASSERT( _WINPLATFORM!=VP_UNKNOWN);

 ///////////////////////////////////
 // Recupère le nom de la machine //
 ///////////////////////////////////
 char szComputerName[MAX_COMPUTERNAME_LENGTH+1];
 DWORD dwSize = MAX_COMPUTERNAME_LENGTH;
 if( ::GetComputerName( szComputerName, &dwSize)) _ComputerName = szComputerName;
                                             else _ComputerName = "NONAME";

 /////////////////////////////////////////////////////
 // Recherche le code pays de la session du Menufed //
 /////////////////////////////////////////////////////
 _CodePays = CP_FRANCE;
 _MoveFile = false;

  try
    {
      BaseDeRegistre = new TRegistry();
      BaseDeRegistre->RootKey = HKEY_LOCAL_MACHINE;
      if (BaseDeRegistre->OpenKey("SOFTWARE\\EIC",false))
        {
          if (BaseDeRegistre->ValueExists("Pays"))
            _CodePays = (CODE_PAYS)BaseDeRegistre->ReadInteger("Pays");
          if (BaseDeRegistre->ValueExists("KernelMoveFile"))
            _MoveFile = BaseDeRegistre->ReadBool("KernelMoveFile");
          BaseDeRegistre->CloseKey();
        }
    }
  catch (Exception &e)
    {
    }
  if (BaseDeRegistre)
    delete BaseDeRegistre;
 if(!(( _CodePays==CP_FRANCE) || ( _CodePays==CP_TUNISIE))) {
   _CodePays = CP_FRANCE;
   ::EICAttention( "La valeur du paramétrage du code pays est incorrecte !\nLe programme sera lancé en mode FRANCE.");
 }
}
//------------------------------------------------------------------------------
__fastcall CInitEICPackage::~CInitEICPackage()
{
  delete _pbmpArrow[0]; _pbmpArrow[0] = NULL;
  delete _pbmpArrow[1]; _pbmpArrow[1] = NULL;
}
//------------------------------------------------------------------------------
static CInitEICPackage InitEICPackage;
//------------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Arrondit un double en long le plus proche
//-----------------------------------------------------------------------------
long __fastcall lArrond(double d)
{
  long l;
  l = long(d);
  if( d > 0.0)
    return ( ( d - l) >= .5) ? ( l + 1) : l;
  else if( d < 0.0)
    return ((d-l)>=-.5) ? l : l-1;
  else
   return 0L;
}
double __fastcall dArrond( double d)
{
  return ((double)lArrond(d * 100.0)) / 100.0;
}
//-----------------------------------------------------------------------------
/*
DOMMAGE MAIS NE FONCTIONNE QUE SOUS SYSTEME NT
AnsiString __fastcall RemoveAccents( const AnsiString &strText)
{
  #define BUFFER_SIZE 1024

  ASSERT( strText.Length()<( BUFFER_SIZE/2));

  char       szTemp[BUFFER_SIZE];
  AnsiString strTemp;

  ::FoldString( MAP_COMPOSITE, strText.c_str(), -1, szTemp, BUFFER_SIZE);
  strTemp = AnsiString( szTemp);

  // Supprime les ( ` ^, ', ¨) de la chaine
  int i = 1;
  while( i<=strTemp.Length()) {
    if(( strTemp[i]=='`'   ) || ( strTemp[i]=='^') ||
       ( strTemp[i]=='\xB4') || ( strTemp[i]=='¨')) strTemp.Delete( i, 1);
                         else i++;
  }

  return strTemp;
}*/
AnsiString __fastcall RemoveAccents( const AnsiString &strText)
{
  AnsiString strAccentLetter( "àâäéèêëiîïoôöùûüyÿçÀÂÄÉÈÊËIÎÏOÔÖÙÛÜYŸÇ");
  AnsiString strNormalLetter( "aaaeeeeiiiooouuuyycAAAEEEEIIIOOOUUUYYC");
  AnsiString strValue( strText);

  for( int i=1; i<=strValue.Length(); i++) {
    int nPos = strAccentLetter.Pos( AnsiString( strValue[i]));
    if( nPos) strValue[i] = strNormalLetter[nPos];
  }
  return strValue;
}




/*
  On commence la numérotation des bits à 1 en partant de la droite.
*/
AnsiString __fastcall BitA0(const AnsiString &Champ,unsigned int NoBit)
{
  if (NoBit == 1)
    return "(CAST(" + Champ + " / 2 AS INTEGER) = CAST((" + Champ + " + 1) / 2 AS INTEGER))";
  else
    return "(CAST(CAST(" + Champ + " / " + pow(2,NoBit - 1) + " AS INTEGER) / 2 AS INTEGER) = CAST((CAST(" + Champ + " / " + pow(2,NoBit - 1) + " AS INTEGER) + 1) / 2 AS INTEGER))";
}
AnsiString __fastcall BitA1(const AnsiString &Champ,unsigned int NoBit)
{
  if (NoBit == 1)
    return "(CAST(" + Champ + " / 2 AS INTEGER) <> CAST((" + Champ + " + 1) / 2 AS INTEGER))";
  else
    return "(CAST(CAST(" + Champ + " / " + pow(2,NoBit - 1) + " AS INTEGER) / 2 AS INTEGER) <> CAST((CAST(" + Champ + " / " + pow(2,NoBit - 1) + " AS INTEGER) + 1) / 2 AS INTEGER))";
}



#define NO_DECIMALES  (-1)
double __fastcall Round(double x, int nDecimales)
{
  if (nDecimales==NO_DECIMALES) return x;
  // Arrondi un montant à N décimales après la virgule
  // avec la méthode suivante
  // Si le (N+1)ième décimale >= 5 on arrondi à la Nième décimale supérieure
  double dValue = pow10( nDecimales); // Exemple :
  double dFract, dEntier;             // x = 123.456                     | x = 654.321

  x = x * dValue;                     // x = 12345.6                     | x = 65432.1
  dFract = modf( x, &dEntier);        // dEntier = 12345 , dFract = 0.6  | dEntier = 65432 , dFract = 0.1
  if ( dFract>=0.5) dEntier++;        // dEntier = 12346                 | dEntier = 65432
  if ( dFract<=-0.5) dEntier--;        // dEntier = 12346                 | dEntier = 65432

  return dEntier / dValue;            // 123.46                          | 654.32
}



__fastcall STRUCT_RACCOURCI::STRUCT_RACCOURCI()
{
  uHotKey = 0;
  iIconLocation = 0;
  memset(&strData,0,sizeof(strData));
}



bool __fastcall CreerRaccourci(STRUCT_RACCOURCI &Raccourci,enum eRACCOURCI uFonction)
{
  HRESULT hres = 0;
  IShellLink* psl;
  try
    {
      switch (uFonction)
        {
          case er_CREATION:
            if (Raccourci.asPathOrigine.IsEmpty())
              return false;
            if (Raccourci.asPathRaccourci.IsEmpty())
              Raccourci.asPathRaccourci = ExtractFilePath(Raccourci.asPathOrigine) + "\\Raccourci de " + ExtractFileName(Raccourci.asPathOrigine) + ".lnk";
            else
              {
                AnsiString asExt = Raccourci.asPathRaccourci.SubString(Raccourci.asPathRaccourci.Length() - 3,4);
                if (asExt.LowerCase() != ".lnk" )
                  Raccourci.asPathRaccourci += ".lnk";
              }
            break;
          case er_LECTURE:
            if (Raccourci.asPathRaccourci.IsEmpty())
              return false;
            break;
          default:
            ASSERT(false);
        }
      hres = CoInitialize(NULL);
      if (!SUCCEEDED(hres))
        return false;
      hres = 0;
      // Get a pointer to the IShellLink interface.
      hres = ::CoCreateInstance(CLSID_ShellLink,NULL,CLSCTX_INPROC_SERVER,IID_IShellLink,(void**)&psl);
      if (SUCCEEDED(hres))
        {
          IPersistFile *ppf;
          if (uFonction == er_CREATION)
            {
              // Set the path to the shortcut target, and add the description.
              psl->SetPath(Raccourci.asPathOrigine.c_str());
              if (!Raccourci.asDescription.IsEmpty())
                psl->SetDescription(Raccourci.asDescription.c_str());
              if (!Raccourci.asLigneDeCommande.IsEmpty())
                psl->SetArguments(Raccourci.asLigneDeCommande.c_str());
              psl->SetHotkey(Raccourci.uHotKey);
              if (!Raccourci.asIconLocation.IsEmpty())
                psl->SetIconLocation(Raccourci.asIconLocation.c_str(),Raccourci.iIconLocation);
              if (!Raccourci.asWorkingDirectory.IsEmpty())
                psl->SetWorkingDirectory(Raccourci.asWorkingDirectory.c_str());
            }
          // Query IShellLink for the IPersistFile interface for saving the
          // shortcut in persistent storage.
          hres = psl->QueryInterface(IID_IPersistFile,(void**)&ppf);
          if (SUCCEEDED(hres))
            {
              WORD wsz[MAX_PATH];
              // Ensure that the string is ANSI.
              MultiByteToWideChar(CP_ACP,0,Raccourci.asPathRaccourci.c_str(),-1,(wchar_t*)wsz,MAX_PATH);
              switch (uFonction)
                {
                  case er_CREATION:
                    // Save the link by calling IPersistFile::Save.
                    hres = ppf->Save((wchar_t*)wsz,true);
                    if (!SUCCEEDED(hres))
                      {
                        ppf->Release();
                        psl->Release();
                        return false;
                      }
                    break;
                  case er_LECTURE:
                    {
                      // load the link by calling IPersistFile::Load.
                      hres = ppf->Load((wchar_t*)wsz,STGM_READ);
                      if (!SUCCEEDED(hres))
                        {
                          ppf->Release();
                          psl->Release();
                          return false;
                        }
                      char szTmp[256];
                      ZeroMemory(&Raccourci.strData,sizeof(WIN32_FIND_DATA));
                      ZeroMemory(szTmp,sizeof(szTmp));
                      psl->GetPath(szTmp,sizeof(szTmp),&Raccourci.strData,SLGP_UNCPRIORITY);
                      Raccourci.asPathOrigine = szTmp;
                      ZeroMemory(szTmp,sizeof(szTmp));
                      psl->GetDescription(szTmp,sizeof(szTmp));
                      Raccourci.asDescription = szTmp;
                      psl->GetHotkey(&Raccourci.uHotKey);
                      int iIconIndex;
                      ZeroMemory(szTmp,sizeof(szTmp));
                      psl->GetIconLocation(szTmp,sizeof(szTmp),&iIconIndex);
                      Raccourci.asIconLocation = szTmp;
                      Raccourci.iIconLocation = iIconIndex;
                      ZeroMemory(szTmp,sizeof(szTmp));
                      psl->GetWorkingDirectory(szTmp,sizeof(szTmp));
                      Raccourci.asWorkingDirectory = szTmp;
                    }
                    break;
                }
              ppf->Release();
            }
          else
            {
              psl->Release();
              return false;
            }
          psl->Release();
        }
      else
        return false;
    }
  catch (Exception &e)
    {
      EICDisplayException(TAGL,e);
    }
  return true;
}

/*******************************************************************************
void __fastcall WriteLog(const AnsiString &aFileName, const AnsiString &aChaine)


Fonction : Ajoute une ligne de texte dans un fichier.
           Cette fonction peut être utilisée pour générer des fichiers Log.

Paramétres d'entrée : aFileName : Nom du fichier Log
                      aChaine : Ligne à ajouter
*******************************************************************************/
void __fastcall WriteLog(const AnsiString &aFileName, const AnsiString &aChaine)
{
FILE *pFile = fopen(aFileName.c_str(), "at");
fputs(AnsiString(aChaine+"\n").c_str(), pFile);
fclose(pFile);
}


/******************************************************************************\
************* EICSplitAbsolutePath() *******************************************
********************************************************************************
*                                                                              *
*   Cette fonction permet de séparer les composantes d'un chemin absolu de la  *
* forme "X:\..." ou "\\ServerName\RootName\...".                               *
*                                                                              *
* Paramètres :                                                                 *
*   strFullPath                                                                *
*   strRootName         : Retourne le nom de la racine (non terminé par '\\'). *
*   strAbsoluteRootDir  : Retourne le chemin absolu à partir de la racine      *
*                         (commence et se termine obligatoirement par '\\').   *
*   strOptionalFileName : Retourne l'éventuel nom du fichier qui figure à la   *
*                         fin du chemin (vide si chemin terminé par '\\').     *
*                                                                              *
* Retour :                                                                     *
*   TRUE si les composantes ont été correctement extraites; FALSE sinon (i.e   *
* le chemin à analyser n'est pas absolu, est incomplet ou contient un          *
* répertoire absolu invalide (avec 2 '\\' consécutifs)).                       *
*                                                                              *
* Notes : + Les paramètres en sortie peuvent être initialisés alaéatoirement   *
*           lorsque la fonction retourne FALSE.                                *
*         + Cette fonction peut être utilisée comme suit pour déterminer si un *
*           nom de chemin ou un nom de fichier est absolu :                    *
*           { AnsiString s;                                                    *
*             if( EICSplitAbsolutePath( strFullPath, s, s, s))                 *
*               if( s.IsEmpty())                                               *
*               { // Chemin terminé par '\\' valide                            *
*               }                                                              *
*               else                                                           *
*               { // Nom de fichier absolu valide                              *
*               }                                                              *
*             else                                                             *
*             { // Chemin ou nom de fichier non absolu                         *
*             }                                                                *
*           }                                                                  *
\******************************************************************************/
bool __fastcall EICSplitAbsolutePath( const AnsiString &strAbsolutePath,
                                      AnsiString       &strRootName,
                                      AnsiString       &strAbsoluteRootDir,
                                      AnsiString       &strOptionalFileName)
{
 const char* pcszPath;          // Partie du chemin absolu en cours d'analyse
 const char* pcszSep;           // Un séparateur
 int         nLen;              // La longueur d'une partie du chemin à extraire
 bool        bDriveIsLowerCase; // TRUE si la lettre qui identifie le lecteur est en minuscule
 const char* pcszTmp;           // Variables temporaires
 char        cTmp;


 /////////////////////////////////
 // Vérification des paramètres //
 /////////////////////////////////
 if( strAbsolutePath.Length() < 3)
   return false;


 ////////////////////////////////////
 // Extraction du nom de la racine //
 ////////////////////////////////////
 cTmp = *( pcszPath = strAbsolutePath.c_str());
 switch( pcszPath[ 1])
 { case ':'  : if( ( pcszPath[ 2] == '\\') &&
                   ( ( ( bDriveIsLowerCase = ( ( cTmp >= 'a') && ( cTmp <= 'z'))) != false) ||
                     ( ( cTmp >= 'A') && ( cTmp <= 'Z'))
                   )
                 )
               { // Racine de la forme "Unité:" suivie d'un chemin absolu
                 nLen = 2;
                 break;
               }
               return false;
   case '\\' : if( ( cTmp == '\\') &&
                   ( ( pcszSep = strchr( pcszPath + 2, '\\')) != NULL) &&
                   ( ( nLen = ( pcszSep - pcszPath)) >= 3) &&
                   ( *++pcszSep != '\\') &&
                   ( ( pcszTmp = strchr( pcszSep, '\\')) != NULL))
               { // Racine de la forme "\\ServerName\RootName" suivie d'un chemin absolu
                 bDriveIsLowerCase = false;
                 nLen              = pcszTmp - pcszPath;
                 break;
               }

   default   : // Chemin non absolu (ni "X:\", ni "\\ServerName\RootName\")
               return false;
 }
 strRootName = AnsiString( pcszPath, (unsigned char)nLen);
 if( bDriveIsLowerCase)
 { // Conversion de la lettre du lecteur en majuscule
   strRootName[ 1] -= (char)( 'a' -'A');
 }


 //////////////////////////////////////////////////
 // Extraction du répertoire relatif à la racine //
 //////////////////////////////////////////////////
 if( ( pcszSep = strrchr( ( pcszPath += nLen) + 1, '\\')) == NULL)
 { // Chemin absolu à la racine ( "\\")
   nLen = 1;
 }
 else
 { // Chemin relatif à la racine
   nLen = pcszSep - pcszPath + 1;
 }
 strAbsoluteRootDir = AnsiString( pcszPath, (unsigned char)nLen);
 if( strstr( strAbsoluteRootDir.c_str(), "\\\\"))
 { // Erreur: Nom de sous-répertoire manquant dans le chemin
   return false;
 }


 //////////////////////////////////////////////
 // Extraction du nom de fichier (optionnel) //
 //////////////////////////////////////////////
 strOptionalFileName = pcszPath + nLen;
 return true;
} /* EICSplitAbsolutePath() */


/******************************************************************************\
************* EICGetFreeSpace() ************************************************
********************************************************************************
*                                                                              *
*   Cette fonction permet de connaître l'espace libre (utilisable par le       *
* processus) d'un périphérique disque local ou réseau.                         *
*                                                                              *
* Paramètres :                                                                 *
*   strAbsolutePath : Un chemin absolu - '\\' final optionnel - sur le         *
*                     périphérique ("U:[...][\]" ou "\\Srv\Root[...][\]").     *
*   u64FreeSpace    : Retourne l'espace libre du périphérique.                 *
*                                                                              *
* Retour :                                                                     *
*   TRUE si l'espace a correctement été lu; FALSE sinon (dans ce cas, zéro est *
* retourné dans le paramètre u64FreeSpace).                                    *
*                                                                              *
* Note : Si le chemin n'existe pas sur le périphérique, la fonction essaye de  *
*        déterminer l'espace libre qui reste à sa racine.                      *
*                                                                              *
* ATTENTION :                                                                  *
* ===========                                                                  *
*    Pour un système antérieur à Win95 OSR2, la taille retournée peut être     *
* invalide (mais inférieur à l'espace libre réel).                             *
*    Pour un périphérique réseau, la requête d'espace libre peut être refusée  *
* par le système ou le serveur; dans ce cas, la taille retournée est           *
* 0xFFFFFFFFFFFFFFFF et ::GetLastError() est positionné à ERROR_NOT_SUPPORTED. *
\******************************************************************************/
bool __fastcall EICGetFreeSpace( const AnsiString &strAbsolutePath,
                                 unsigned __int64 &u64FreeSpace)
{
 typedef BOOL WINAPI (*TGetDiskFreeSpaceEx)( LPCSTR          lpDirectoryName,
                                             PULARGE_INTEGER lpFreeBytesAvailableToCaller,
                                             PULARGE_INTEGER lpTotalNumberOfBytes,
                                             PULARGE_INTEGER lpTotalNumberOfFreeBytes
                                           );

 AnsiString strDevicePath( strAbsolutePath); // Répertoire absolu du périphérique
 AnsiString strRootName;                     // Racine du périphérique
 AnsiString strAbsoluteRootDir;              // Répertoire à partir de la racine du périphérique
 HINSTANCE  hLibKernel32;                    // Handle du kernel 32 bits


 /////////////////////////////////////////////
 // Extraction de la racine du périphérique //
 /////////////////////////////////////////////
 if( *strDevicePath.AnsiLastChar() != '\\')
   strDevicePath += "\\";
 if( !EICSplitAbsolutePath( strDevicePath, strRootName, strAbsoluteRootDir, AnsiString()))
 { // Erreur: Le chemin indiqué n'est pas absolu
   u64FreeSpace = 0;
   return false;
 }


 ////////////////////////////////////////////////////
 // Tentative d'utilisation de la fonction étendue //
 ////////////////////////////////////////////////////
 if( ( hLibKernel32 = ::GetModuleHandle( "KERNEL32")) != NULL)
 {
   TGetDiskFreeSpaceEx pfnGetDiskFreeSpaceEx;
   ULARGE_INTEGER      ulFreeCallerBytes, ulTotalBytes;

   #ifdef UNICODE
    #define NAMEGetDiskFreeSpaceEx "GetDiskFreeSpaceExW"
   #else
    #define NAMEGetDiskFreeSpaceEx "GetDiskFreeSpaceExA"
   #endif
   if( ( pfnGetDiskFreeSpaceEx = (TGetDiskFreeSpaceEx)GetProcAddress( hLibKernel32, NAMEGetDiskFreeSpaceEx)) != NULL)
   { // Nous sommes sur un système >= Win95 OSR2
     for( bool bRetryWithRoot = false;;)
     {
       if( pfnGetDiskFreeSpaceEx( strDevicePath.c_str(), &ulFreeCallerBytes, &ulTotalBytes, NULL))
       { // Espace libre lu avec succès
         u64FreeSpace = ulFreeCallerBytes.QuadPart;
         return true;
       }
       else if( !bRetryWithRoot && ( ::GetLastError() == ERROR_FILE_NOT_FOUND))
       { // Répertoire non trouvé sur le périphérique
         // => On réessaye avec la racine
         strDevicePath  = strRootName;
         bRetryWithRoot = true;
         continue;
       }
       else
       { // Erreur: Impossible de lire l'espace libre restant (dans le chemin ou la racine du périphérique)
         u64FreeSpace = 0;
         return false;
       }
     }
   }
   #undef NAMEGetDiskFreeSpaceEx
 }


 /////////////////////////////////////////
 // Utilisation de la fonction standard //
 /////////////////////////////////////////
 DWORD dwSectorsPerCluster, dwBytesPerSector, dwNbFreeClusters, dwNbTotalClusters;

 ASSERT( *strRootName.AnsiLastChar() != '\\');
 if( ::GetDiskFreeSpace( ( strRootName + "\\").c_str(), &dwSectorsPerCluster, &dwBytesPerSector, &dwNbFreeClusters, &dwNbTotalClusters))
 { // Espace libre Ok
   u64FreeSpace = (unsigned __int64)dwNbFreeClusters * (unsigned __int64)dwSectorsPerCluster * (unsigned __int64)dwBytesPerSector;
 }
 else if( ::GetLastError() == ERROR_NOT_SUPPORTED)
 { // Lecture sur un périphérique réseau refusée
   // => On suppose que tout est Ok et on renvoie la taille maximale
   u64FreeSpace = ~0;
 }
 else
 { // Erreur: Lecture de l'espace libre impossible
   u64FreeSpace = 0;
   return false;
 }
 return true;
} /* EICDiskFreeSpace() */

/*******************************************************************************
bool __fastcall VerInternetExplorerSup3()

Fonction : L'aide RoboHelp nécessite Internet Explorer 4 minimum.
   Cette fonction vérifie sa présence

Paramètre retournée : true si au moins Internet Explorer 4 est installé
*******************************************************************************/
bool __fastcall VerInternetExplorerSup3()
{
TRegistry    *Regist      = NULL;
AnsiString    aPathKey   = "\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\APP PATHS\\IEXPLORE.EXE";
AnsiString aAdr_IE_Exe; //Chemin et nom de l'éxecutable d'internet Explorer
AnsiString aDllVer;
bool bRetour = false;

try
   {
   Regist           = new TRegistry;
   Regist->RootKey = HKEY_LOCAL_MACHINE;
   Regist->Access  = KEY_READ;
   if(Regist->KeyExists(aPathKey))
      {
      if( Regist->OpenKey( aPathKey, false ))
         {
         aAdr_IE_Exe = Regist->ReadString("");
         //SI IEXPLORE.EXE est présent
         //ET SI On a pu récupérer son numéro de version
         //ET SI sa version est supérieure ou égale à la 4.72
         if (   FileExists(aAdr_IE_Exe)
             && (aDllVer = GetDLLVer (aAdr_IE_Exe)) != VER_DLL_INCONNUE
              && (   atoi(&aDllVer[1]) > 4
                  || atoi(&aDllVer[1]) == 4 && atoi(&aDllVer[3]) >= 72))
            bRetour = true;
         Regist->CloseKey();
         }
      }
   }

catch( Exception &e )
   {
   EICDisplayException( TAGL, e );
   }
delete Regist;
return bRetour;
}

//-----------------------------------------------------------------------------
/*                              bool __fastcall IsAdmin()
// Renvoie true si on est administrateur du poste
// Remarque : Sous Windows 9x, renvoie toujours true
*/
//-----------------------------------------------------------------------------
bool __fastcall IsAdmin()
{
   HANDLE          hToken = NULL;
   PSID            pAdminSid = NULL;
   BYTE            buffer[1024];
   PTOKEN_GROUPS   pGroups = (PTOKEN_GROUPS)buffer;
   DWORD           dwSize;             // buffer size
   DWORD           i;
   BOOL            bSuccess;
   SID_IDENTIFIER_AUTHORITY siaNtAuth = SECURITY_NT_AUTHORITY;

   // Si Sytème Win9x, toujours renvoyer true
   if (_WINPLATFORM == VP_WINDOWS_95_98)
    return true;

   if ( !OpenProcessToken ( GetCurrentProcess ( ), TOKEN_QUERY, &hToken ) )
       return false;

   bSuccess = GetTokenInformation ( hToken, TokenGroups,
                                   (LPVOID)pGroups, 1024,
                                   &dwSize );
   CloseHandle ( hToken );
   if ( !bSuccess )
       return false;
   if ( !AllocateAndInitializeSid ( &siaNtAuth, 2,
                                    SECURITY_BUILTIN_DOMAIN_RID,
                                    DOMAIN_ALIAS_RID_ADMINS,
                                    0,0,0,0,0,0, &pAdminSid ) )
       return false;

   bSuccess = false;
   for ( i = 0; (i < pGroups->GroupCount) && !bSuccess; i++ )
   {
       if ( EqualSid ( pAdminSid, pGroups->Groups[i].Sid ) )
           bSuccess = true;
   }
   FreeSid ( pAdminSid );

   return bSuccess;
}
//-----------------------------------------------------------------------------
const GUID CLSID_MSDiscRecorderObj = {0x520CCA61,0x51A5,0x11D3,{0x91,0x44,0x00,0x10,0x4B,0xA1,0x1C,0x5E}};
const GUID IID_IDiscRecorder = {0x85AC9776, 0xCA88, 0x4CF2,{ 0x89, 0x4E, 0x09,0x59, 0x8C, 0x07,0x8A, 0x41} };
const GUID CLSID_MSDiscMasterObj = {0x520CCA63,0x51A5,0x11D3,{0x91,0x44,0x00,0x10,0x4B,0xA1,0x1C,0x5E}};
const GUID IID_IDiscMaster = {0x520CCA62,0x51A5,0x11D3,{0x91,0x44,0x00,0x10,0x4B,0xA1,0x1C,0x5E}};
const GUID CLSID_MSEnumDiscRecordersObj = {0x08A03567A,0x63CB,0x4BA8,{0xBA,0xF6,0x52,0x11,0x98,0x16,0xD1,0xEF}};
const GUID IID_IEnumDiscRecorders = {0x9B1921E1,0x54AC,0x11d3,{0x91,0x44,0x00,0x10,0x4B,0xA1,0x1C,0x5E}};
//-----------------------------------------------------------------------------
AnsiString __fastcall GetDrive(const AnsiString &asDevice)
{
    char szDevice[1024];
    char Lecteurs[255],Lettre;
    memset(Lecteurs,'\0',255);
    GetLogicalDriveStrings(255,Lecteurs);
    for (int i = 0;i < 255;i++)
    {
      if ((Lecteurs[i] >= 'A') && (Lecteurs[i] <= 'Z')) {
        Lettre = Lecteurs[i];
        QueryDosDevice((AnsiString(Lettre)+":").c_str(), szDevice, 1024);
        if (AnsiString(szDevice) == asDevice) break;
      }
    }
    return (AnsiString(Lettre));
}
//-----------------------------------------------------------------------------
bool __fastcall IsGraveur(const AnsiString &asPath)
{
    bool bRetour = false;
    HRESULT hresDiscMaster/*, hresEnumDiscRecorders/*, hresDiscRecorder*/;
    IDiscMaster *DiscMaster;
    IEnumDiscRecorders* EnumDiscRecorders;
    IDiscRecorder* DiscRecorder;

    CoInitialize(NULL);

    hresDiscMaster = CoCreateInstance(CLSID_MSDiscMasterObj, NULL, CLSCTX_ALL, IID_IDiscMaster, (LPVOID *)&DiscMaster);
//    hresEnumDiscRecorders = CoCreateInstance(CLSID_MSEnumDiscRecordersObj, NULL, CLSCTX_ALL, IID_IEnumDiscRecorders, (LPVOID *)&EnumDiscRecorders);
//    hresDiscRecorder = CoCreateInstance(CLSID_MSDiscRecorderObj, NULL, CLSCTX_ALL, IID_IDiscRecorder, (LPVOID *)&DiscRecorder);

    if ((hresDiscMaster == S_OK)/*&&(hresEnumDiscRecorders == S_OK) &&(hresDiscRecorder == S_OK)*/)   {
        DiscMaster->Open();
        DiscMaster->EnumDiscRecorders(&EnumDiscRecorders);
        ULONG l = 0, compt = 0;
        while( (EnumDiscRecorders->Next(1, &DiscRecorder, &l)) != 1)
        {
                compt++;
                long fTypeCode;
                DiscRecorder->GetRecorderType(&fTypeCode);
                if(fTypeCode ==  RECORDER_CDRW || fTypeCode ==  RECORDER_CDR)  {
                        BSTR bsz[ MAX_PATH];
                        DiscRecorder->GetPath(bsz);
                        if (GetDrive(AnsiString(*bsz)) == asPath) bRetour = true;
                }
                DiscRecorder->Release();
        }
        if( !compt) bRetour = false;
        EnumDiscRecorders->Release();
        DiscMaster->Close();
    }else
        bRetour = false;
//    if( SUCCEEDED(hresDiscRecorder))       DiscRecorder->Release();
//    if( SUCCEEDED(hresEnumDiscRecorders))       EnumDiscRecorders->Release();
    if( SUCCEEDED(hresDiscMaster))              DiscMaster->Release();
    CoUninitialize();
    return bRetour;
}
//-----------------------------------------------------------------------------
bool __fastcall CanCreateFile( const AnsiString &strPath)
{
  AnsiString strTestFile( IncludeTrailingBackslash( strPath) + "tstfile.eic");

  bool bResult   = false;
  UINT unErrMode = ::SetErrorMode( SEM_FAILCRITICALERRORS);
  FILE *file     = fopen( strTestFile.c_str(), "wb");
  ::SetErrorMode( unErrMode);
  bResult = ( file!=NULL);
  if( file) {
    fclose( file);
    DeleteFile( strTestFile);
  }
  return bResult;
}
//-----------------------------------------------------------------------------
#define CSIDL_CDBURN_AREA    0x003b
//-----------------------------------------------------------------------------
AnsiString __fastcall RedirectPathForCreateFile(const AnsiString &asPath)
{
  char szPath[MAX_PATH];
  CBarre     eBarre;
  AnsiString asDrive = ExtractFileDrive( asPath);
  AnsiString asPathSansDrive = asPath.SubString( asDrive.Length() + 1, asPath.Length());
  static AnsiString _strBurnerDrive; // stocké pour ne pas refaire la rcherche
  static AnsiString _strBurnerPath;

  if( !_strBurnerDrive.IsEmpty() && ( asDrive==_strBurnerDrive)) return _strBurnerPath + asPathSansDrive;

  if( GetDriveType( asDrive.c_str())==DRIVE_CDROM) {
    eBarre.Titre = "Recherche le type du lecteur";
    eBarre.Open();
    ASSERT( asDrive.Length()==2);
    ASSERT( asDrive[2]==':');
    if( IsGraveur( asDrive.SubString( 1, 1)) && !CanCreateFile( asPath)) {
      LPITEMIDLIST idFolder;
      SHGetSpecialFolderLocation( Application->Handle, CSIDL_CDBURN_AREA, &idFolder);
      SHGetPathFromIDList( idFolder, szPath);
      //SHGetSpecialFolderPath( Application->Handle, szPath, CSIDL_CDBURN_AREA, false);
      _strBurnerDrive = asDrive;
      _strBurnerPath  = ExcludeTrailingBackslash( szPath);
      return ( _strBurnerPath + asPathSansDrive);
    } else {
      return asPath;
    }
  }

  return asPath;
}


eWindows __fastcall GetVersionDeWindows()
{
  OSVERSIONINFO OSVersion;
  OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  if (GetVersionEx(&OSVersion))
    {
      switch (OSVersion.dwMajorVersion)
        {
          case 3:
            switch (OSVersion.dwMinorVersion)
              {
                case 51:
                  return eWinNT351;
              }
            break;
          case 4:
            switch (OSVersion.dwMinorVersion)
              {
                case 0:
                  if (OSVersion.dwPlatformId == VER_PLATFORM_WIN32_NT)
                    return eWinNT40;
                  else
                    return eWin95;
                case 10:
                  return eWin98;
                case 90:
                  return eWinMe;
              }
            break;
          case 5:
            switch (OSVersion.dwMinorVersion)
              {
                case 0:
                  return eWin2000;
                case 1:
                  return eWinXP;
                case 2:
                  return eWinNETServer;
              }
            break;
          case 6:
            if (OSVersion.dwMinorVersion == 0)
               return eWinVista;
            break;
        }
    }
  return eWinInconnu;
}

int __fastcall GetVersionDeServicePack()
{
int iServicePack = 0;
OSVERSIONINFO OSVersion;

 OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
 if (::GetVersionEx(&OSVersion))
    {
    try
       {
       if (strlen(OSVersion.szCSDVersion) >= 13)
          sscanf(&(char)OSVersion.szCSDVersion[13], "%i", &iServicePack);
       }
    catch(Exception &e)
       {
       ASSERT(false);
       }
    }
return iServicePack;
}

//-----------------------------------------------------------------------------
double __fastcall EICStr2Double( const AnsiString &strValue)
{
  AnsiString str( strValue);
  int        nIndex = str.LastDelimiter( ".,");

  if( nIndex) str[nIndex] = DecimalSeparator;
  return str.ToDouble();
}
//-----------------------------------------------------------------------------
Currency __fastcall EICStr2Currency( const AnsiString &strValue)
{
  return EICStr2Double( strValue);
}
//-----------------------------------------------------------------------------
//Convertit un montant en AnsiString en remplaçant la virgule par le point
//Utilisé pour les requêtes SQL
AnsiString __fastcall EICMontantToChaine(const Currency &Montant)
{
  AnsiString asStr = AnsiString(Montant);
  int i = asStr.LastDelimiter(",");
  if (i)
    asStr[i] = '.';
  return asStr;
}

//-----------------------------------------------------------------------------
//Convertit un montant en AnsiString en remplaçant la virgule par le point
//Utilisé pour les requêtes SQL
AnsiString __fastcall EICMontantToChaine(const double &Montant)
{
  if(Montant == D_NS) return "NULL";
  AnsiString asStr = AnsiString(Montant);
  int i = asStr.LastDelimiter(",");
  if (i)
    asStr[i] = '.';
  return asStr;
}

/*******************************************************************************
void __fastcall EncryptPassword( const AnsiString &strPassword, char *szBuffer)

Fonction : Crypte une chaîne

Paramètres d'entrée : strPassword

Paramètres de sortie : szBuffer : Mot de passe crypté. Cette chaîne doit contenir
                                  un caractère de plus que le mot de passe à crypter.

*******************************************************************************/
void __fastcall EncryptPassword( const AnsiString &strPassword, char *szBuffer)
{
  szBuffer[0] = ( char)strPassword.Length();

  for( int i=1; i<=strPassword.Length(); i++)
    szBuffer[i] = strPassword[i] ^ ( char)( 0x69) ^ ( char)i;
}
//---------------------------------------------------------------------------
AnsiString __fastcall DecryptPassword( char *szBuffer)
{
  AnsiString strPass;
             strPass.SetLength( szBuffer[0]);

  for( int i=1; i<=( int)szBuffer[0]; i++)
    strPass[i] = szBuffer[i] ^ ( char)( 0x69) ^ ( char)i;

  return strPass;
}
//---------------------------------------------------------------------------
// Si chemin commence par / alors ajout de / à la fin
// Si chemin commence par \ ou 2ème lettre : alors ajout de \ à la fin
//---------------------------------------------------------------------------
AnsiString AddSlash( const AnsiString &_asChaine)
{
AnsiString asRetour = _asChaine;
    if (!_asChaine.IsEmpty()) {
        int nPos = _asChaine.Pos(":");
        if (    (_asChaine[1] == '/')
            ||  ((nPos != 0) && (_asChaine[nPos +1] == '/'))) {
            if (_asChaine[_asChaine.Length()] != '/') {
                asRetour += "/";
            }
        } else {
            if (_asChaine[_asChaine.Length()] != '\\') {
                asRetour += "\\";
            }
        }
    }
return asRetour;
}
//---------------------------------------------------------------------------

/*bool __fastcall PosteTSE()
{
  BaseArGistreMenufed BaseDeRegistre;
  if (!BaseDeRegistre.CleExiste(ec_TSEnabled))
    return false;
  if (VersionDeWindows() == eWinNT40)
    return true;
  return BaseDeRegistre.TSEnabled == 1;
}     */


AnsiString __fastcall PremierFichierLibre(const AnsiString &Fichier)
{
  int Nb = 1;
  AnsiString Chemin,Nom,Extension,NouveauNom;
  if (!FileExists(Fichier))
    return Fichier;
  Chemin = ExtractFilePath(Fichier);
  Nom = ExtractFileName(Fichier);
  Extension = ExtractFileExt(Nom);
  Nom = ChangeFileExt(Nom,EmptyStr);
  do
    {
      do
        {
          NouveauNom = Nom + Nb;
          if (NouveauNom.Length() <= 8)
            break;
          Nom = Nom.SubString(1,Nom.Length() - 1);
        }
      while (true);
      Nb++;
      NouveauNom = IncludeTrailingBackslash(Chemin) + NouveauNom + Extension;
    }
  while (FileExists(NouveauNom));
  return NouveauNom;
}



const char TableConversionMACAnsi[256] =
{                        // Les caractères non reconnus sont remplacés par un espace
  "         \t\n  \r  "  //00-0F caractères non imprimables
  "                "     //10-1F caractères non imprimables
  " !\"#$%&'()*+,-./"    //20-2F
  "0123456789:;<=>?"     //30-3F
  "@ABCDEFGHIJKLMNO"     //40-4F
  "PQRSTUVWXYZ[\\]^_"    //50-5F
  "`abcdefghijklmno"     //60-6F
  "pqrstuvwxyz{|}~¦"     //70-7F
  "ÄÅÇÉÑÖÜaàâäãåçéè"     //80-8F
  "êëIÌÎÏñoòôöõuùûü"     //90-9F
  "†°¢£§•¶ß®©™'¨#ÆØ"     //A0-AF
  " ±<>¥µ     ao æø"     //B0-BF
  "¿¡¬ ƒ„ «»… ÀÁÓŒœ"     //C0-CF
  "–—“”‘’÷ ÿŸ/€ ¸  "     //D0-DF
  "‡·, ‰ÂÊÁËÈÍÎÏÌÓÔ"     //E0-EF
  " ÒÚÛÙ|^~¯¨ °    "     //F0-FF
};
AnsiString &__fastcall MACToChar(AnsiString &Chaine)
{
  for (int i = 1;i <= Chaine.Length();i++)
    Chaine[i] = TableConversionMACAnsi[(unsigned char)Chaine[i]];
  return Chaine;
}
void __fastcall MACToChar(char *Chaine,unsigned int MaxLength)
{
  unsigned int n = 0;
  unsigned char *c = Chaine;
  while ((n++ < MaxLength) && *c)
    *(c++) = TableConversionMACAnsi[*c];
}



//Teste si un n° SIRET est correct
bool __fastcall EstUnSIRET(const AnsiString &strSIRET)
{
  bool bResult = false;
  int iSomme = 0, iTmp;
  AnsiString sChiffres("0123456789");
  if (strSIRET.Length() == 14)
  {
    for (int i = 1; i <= strSIRET.Length(); i++)
      if (!sChiffres.Pos(strSIRET[i]))
      {
        EICAttention("Le SIRET saisi contient des caractères non numériques.\nVeuillez vérifier votre saisie.");
        return false;
      }
    /*********************************************
    Vérification du SIREN (9 premiers caractères)
    On multiplie les chiffres de rang pair par 2
    On multiplie les chiffres de rang impair par 1
    La somme des chiffres obtenus est un multiple de 10 si le N° est exact
    ex : soit le SIREN 732 829 320
    Pour vérifier : 7 3 2 8 2 9 3 2 0
    rang pair * 2     6   16  18  4
    rang impait *1  7   2   2   3   0
    Somme : 7+6+2+1+6+2+1+8+3+4+0 = 40
    Le SIREN est exact
    **********************************************/
    for (int i = 1; i <= 9 ; i += 2)
      iSomme += StrToInt(strSIRET.SubString(i,1));
    for (int i = 2; i <= 8; i += 2)
    {
      iTmp = StrToInt(strSIRET.SubString(i,1)) * 2;
      if (iTmp >= 10)
      {
        iSomme += 1;
        iSomme += iTmp % 10;
      }
      else
        iSomme += iTmp;
    }
    if (iSomme % 10 != 0)
      bResult = false;
    else
    {
      /*********************************************
      Vérification du SIRET(14 caractères)
      On multiplie les chiffres de rang pair à partir de la droite par 2
      On multiplie les chiffres de rang impair par 1
      La somme des chiffres obtenus est un multiple de 10 si le N° est exact
      ex : soit le SIRET 732 829 320 00074
      Pour vérifier : 7 3 2 8 2 9 3 2 0 0 0 0 7 4
      rang pair * 2  14   4   4   6   0   0  14
      rang impait *1    3   8   9   2   0   0   4
      Somme : 1+4+3+4+8+4+9+6+2+0+0+0+0+1+4+4=50
      Le SIREN est exact
      **********************************************/
      for (int i = 2; i <= 14 ; i+=2)
        iSomme += StrToInt(strSIRET.SubString(i,1));
      for (int i = 1; i <= 13; i+=2)
      {
        iTmp = StrToInt(strSIRET.SubString(i,1)) * 2;
        if (iTmp >= 10)
        {
          iSomme += 1;
          iSomme += iTmp % 10;
        }
        else
          iSomme += iTmp;
      }
      if (iSomme % 10 != 0)
        bResult = false;
      else
        bResult = true;
    }
  }
  return bResult;
}
//---------------------------------------------------------------------------
int _cdecl EstUnSIRETC( const char* pszSiret)
{
  return( (int)EstUnSIRET( AnsiString( pszSiret)) );
}
//---------------------------------------------------------------------------

bool __fastcall VerificationDuSIRET(const AnsiString &strSIRET)
{
  if (EstUnSIRET(strSIRET))
    return true;
  else return (EICQuestion("Le SIRET saisi n'est pas correct. Confirmez-vous la sortie de cet écran ?","SIRET incorrect",MB_DEFBUTTON2));
}
//---------------------------------------------------------------------------
int _cdecl VerificationDuSIRETC( const char* pszSiret)
{
  return( (int)VerificationDuSIRET( AnsiString( pszSiret)) );
}
/*******************************************************************************
void __fastcall SemicolonTextToStringList(const char AnsiString &aSemiColonText, TStringList *slTexte)

Fonction : Découpe une chaîne en plusieurs éléments, chaque élément devant être délimité par un point-virgule.

Paramètres d'entrée :

Paramètres de sortie :

Valeur retournée :
*******************************************************************************/
void __fastcall SemicolonTextToStringList(const AnsiString &aSemiColonText, TStringList *slTexte)
{
int i;
int iDebut = 1;
try
   {
   for (i=1 ; i<aSemiColonText.Length() ; i++)
      {
      if (aSemiColonText[i] == ';')
         {
         //On ajoute du début, jusqu'au caractère qui précède le ;
         slTexte->Add(aSemiColonText.SubString(iDebut, i-1 - iDebut + 1));
         iDebut = i+1;
         }
      }
   if (iDebut < i)
      //On ajoute du début jusqu'au dernier caractère
      slTexte->Add(aSemiColonText.SubString(iDebut, i - iDebut + 1 + (aSemiColonText[i] == ';' ? -1 : 0)));
   }
catch( Exception &e )
   {
   EICDisplayException( TAGL, e );
   }
}

/*******************************************************************************
void __fastcall MaskBmp(Graphics::TBitmap *Bmp, TColor TransparentColor)

Fonction : Passe l'image en Monochrome pour une utilisation en tant que mask

           Sur certains Windows XP, l'affectation à true de la propriété Monochrome
           donne une image noire, qui ne prend pas en compte la couleur de
           transparence (bug de BitBlt). Ce qui nous obligé à utiliser cette fonction.

Paramètres d'entrée : TransparentColor

Paramètres modifiés : Bmp
*******************************************************************************/
void __fastcall MaskBmp(Graphics::TBitmap *Bmp, TColor TransparentColor)
{
try
   {
   for (int x=0 ; x<Bmp->Width ; x++)
      for (int y=0 ; y<Bmp->Height ; y++)
         if (GetPixel(Bmp->Canvas->Handle, x, y) == (COLORREF)TransparentColor)
            SetPixel(Bmp->Canvas->Handle, x, y, clWhite);
         else
            SetPixel(Bmp->Canvas->Handle, x, y, clBlack);
   }
catch(Exception &e)
   {
   EICDisplayException(TAGL, e );
   }
}

AnsiString __fastcall GetUniqueFileName( const AnsiString &strPath, const AnsiString &strPrefix, const AnsiString &strExt)
{
  char szFileName[MAX_PATH+1];
  if( GetTempFileName( strPath.c_str(), strPrefix.c_str(), 0, szFileName)==0) return EmptyStr;
  AnsiString strNewFileName( ChangeFileExt( szFileName, strExt));
  if( FileExists( strNewFileName)) strNewFileName = GetUniqueFileName( strPath, strPrefix, strExt);
  ::DeleteFile( szFileName);
  return strNewFileName;
}


/*******************************************************************************

Fonction : Change la TransparentColor de Bmp en FondColor

Paramètres d'entrée :

Paramètres modifiés : Bmp
*******************************************************************************/
void __fastcall CreerTransparenceBmp(Graphics::TBitmap *Bmp,
                                     TColor TransparentColor,
                                     TColor FondColor
                                     )
{
Graphics::TBitmap *pBmpGlyphMask  = NULL; pBmpGlyphMask  = new Graphics::TBitmap();
Graphics::TBitmap *pBmpGlyphFond  = NULL; pBmpGlyphFond  = new Graphics::TBitmap();
try
   {
   pBmpGlyphFond->Height = Bmp->Height;
   pBmpGlyphFond->Width  = Bmp->Width ;
   pBmpGlyphFond->Canvas->Brush->Color = clBtnFace;
   pBmpGlyphFond->Canvas->FillRect(pBmpGlyphFond->Canvas->ClipRect);

   //Création du mask : la transparence est blanche (0xFFFFFF) et le reste est noir (0x000000)
   pBmpGlyphMask->Assign(Bmp);
   MaskBmp(pBmpGlyphMask, pBmpGlyphMask->Canvas->Pixels[0][0]);

   //On fusionne le fond et le mask => La zone non transparente du fond devient noire (0x00)
   pBmpGlyphFond->Canvas->CopyMode = cmSrcAnd;
   pBmpGlyphFond->Canvas->Draw(0, 0, pBmpGlyphMask);

   //Inversion du mask : La zone transparente devient noire (0x000000)
   pBmpGlyphMask->Canvas->CopyMode = cmNotSrcCopy;
   pBmpGlyphMask->Canvas->Draw(0, 0, pBmpGlyphMask);

   //On applique le mask inversé à l'image => le fond de l'image devient noir (0x000000)
   Bmp->Canvas->CopyMode = cmSrcAnd;
   Bmp->Canvas->Draw(0, 0, pBmpGlyphMask);

   //On fusionne l'image avec le fond (OU)
   Bmp->Canvas->CopyMode = cmSrcPaint;
   Bmp->Canvas->Draw(0, 0, pBmpGlyphFond);
   }
catch(Exception &e)
   {
   EICDisplayException(TAGL, e );
   }
delete pBmpGlyphMask;
delete pBmpGlyphFond;
}
//-----------------------------------------------------------------------------
// Calcul le nombre de pixel nécessaire en fonction du la taille en PPP
//-----------------------------------------------------------------------------
int __fastcall CalculPixelPourPPP( int _nValeur, int _nConceptionPPP )
{
int nRetour = 0;
try {
	HDC hDW = CreateCompatibleDC(NULL);
	
    int nWinPPP = GetDeviceCaps(hDW, LOGPIXELSX);

	if ((nWinPPP != 0) && (_nValeur != 0) && (_nConceptionPPP != 0))
			nRetour = (nWinPPP * _nValeur) / _nConceptionPPP;
		
	DeleteDC(hDW);
	
    } catch( Exception &e ) {
        EIC_DISPLAY_EXCEPTION( e);
        nRetour = 0;
    }
return nRetour;
}
/*******************************************************************************
short __fastcall CompareVersion(AnsiString aVersion1, AnsiString aVersion2)

Fonction : Compare deux numéros de version structurée de la manière suivante : 2.10.20.1250

Paramètres d'entrée :

Paramètres modifiés :

Valeur retournée : Si Version1 = Version2 ---> Retourne 0
                   Si Version1 < Version2 ---> Retourne valeur < 0
                   Si Version1 > Version2 ---> Retourne valeur > 0
*******************************************************************************/
short __fastcall CompareVersion(AnsiString aVersion1, AnsiString aVersion2)
{
    short shRetour = 0;
    TStringList *lVersion1 = NULL;
    TStringList *lVersion2 = NULL;
    int nVersion1, nVersion2;
    try {
        // La version est composée des versions Majeure, Mineure, Sous-version et Construction

        lVersion1 = new TStringList();
        lVersion2 = new TStringList();

        // On remplace les séparateur de type '.' en ';' pour pouvoir utiliser
        // la fonction CommaText d'une TStringList
        aVersion1 = StringReplace(aVersion1, ".", ",", TReplaceFlags() << rfReplaceAll);
        aVersion2 = StringReplace(aVersion2, ".", ",", TReplaceFlags() << rfReplaceAll);


        lVersion1->CommaText = (aVersion1.IsEmpty())? (AnsiString)"0" : aVersion1;
        lVersion2->CommaText = (aVersion2.IsEmpty())? (AnsiString)"0" : aVersion2;

        for (int i=0; i< lVersion1->Count; i++) {

            nVersion1 = lVersion1->Strings[i].ToIntDef(0);
            nVersion2 = lVersion2->Strings[i].ToIntDef(0);

                 if (nVersion1 < nVersion2) { shRetour = -1; break; }
            else if (nVersion1 > nVersion2) { shRetour = 1;  break; }
        }

    } catch(Exception &e) {
        EIC_DISPLAY_EXCEPTION(e ); }

    if (lVersion1) { delete lVersion1; lVersion1 = NULL; }
    if (lVersion2) { delete lVersion2; lVersion2 = NULL; }

    return shRetour;
}
//-----------------------------------------------------------------------------

